Repository: freqtrade/freqtrade

Issue:
Market orders are not handled in persistence.
## Summary
As part of  #1330, I think we have missed the persistence layer.   

Only 'limit' is accepted as valid in persistence: 

```
if order_type == 'limit' and order['side'] == 'buy':
            # Update open rate and actual amount
            self.open_rate = Decimal(order['price'])
            self.amount = Decimal(order['amount'])
            logger.info('LIMIT_BUY has been fulfilled for %s.', self)
            self.open_order_id = None
        elif order_type == 'limit' and order['side'] == 'sell':
            self.close(order['price'])
        elif order_type == 'stop_loss_limit':
            self.stoploss_order_id = None
            logger.info('STOP_LOSS_LIMIT is hit for %s.', self)
            self.close(order['average'])
        else:
            raise ValueError(f'Unknown order type: {order_type}')
```

## Logs
```
A  2018-12-21 10:27:24,440 - freqtrade.persistence - INFO - Updating trade (id=4) ...

A  2018-12-21 10:27:24,440 - freqtrade - ERROR - Fatal exception!

A  Traceback (most recent call last):

A    File "/freqtrade/freqtrade/main.py", line 49, in main

A      state = freqtrade.worker(old_state=state)

A    File "/freqtrade/freqtrade/freqtradebot.py", line 122, in worker

A      min_secs=min_secs)

A    File "/freqtrade/freqtrade/freqtradebot.py", line 134, in _throttle

A      result = func(*args, **kwargs)

A    File "/freqtrade/freqtrade/freqtradebot.py", line 174, in _process

A      state_changed |= self.process_maybe_execute_sell(trade)

A    File "/freqtrade/freqtrade/freqtradebot.py", line 502, in process_maybe_execute_sell

A      trade.update(order)

A    File "/freqtrade/freqtrade/persistence.py", line 265, in update

A      raise ValueError(f'Unknown order type: {order_type}')

A  ValueError: Unknown order type: market
```


Discussion:
as a side note - why on earth are we only logging on buy - but not when `sell` is fullfilled ... ? 
well we should add that log :/ 

Resolving patch:
diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py
--- a/freqtrade/persistence.py
+++ b/freqtrade/persistence.py
@@ -247,16 +247,17 @@ def update(self, order: Dict) -> None:
         if order['status'] == 'open' or order['price'] is None:
             return
 
-        logger.info('Updating trade (id=%d) ...', self.id)
+        logger.info('Updating trade (id=%s) ...', self.id)
 
-        if order_type == 'limit' and order['side'] == 'buy':
+        if order_type in ('market', 'limit') and order['side'] == 'buy':
             # Update open rate and actual amount
             self.open_rate = Decimal(order['price'])
             self.amount = Decimal(order['amount'])
-            logger.info('LIMIT_BUY has been fulfilled for %s.', self)
+            logger.info('%s_BUY has been fulfilled for %s.', order_type.upper(), self)
             self.open_order_id = None
-        elif order_type == 'limit' and order['side'] == 'sell':
+        elif order_type in ('market', 'limit') and order['side'] == 'sell':
             self.close(order['price'])
+            logger.info('%s_SELL has been fulfilled for %s.', order_type.upper(), self)
         elif order_type == 'stop_loss_limit':
             self.stoploss_order_id = None
             logger.info('STOP_LOSS_LIMIT is hit for %s.', self)


Test patch:
diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py
--- a/freqtrade/tests/conftest.py
+++ b/freqtrade/tests/conftest.py
@@ -387,6 +387,36 @@ def limit_buy_order():
     }
 
 
+@pytest.fixture(scope='function')
+def market_buy_order():
+    return {
+        'id': 'mocked_market_buy',
+        'type': 'market',
+        'side': 'buy',
+        'pair': 'mocked',
+        'datetime': arrow.utcnow().isoformat(),
+        'price': 0.00004099,
+        'amount': 91.99181073,
+        'remaining': 0.0,
+        'status': 'closed'
+    }
+
+
+@pytest.fixture
+def market_sell_order():
+    return {
+        'id': 'mocked_limit_sell',
+        'type': 'market',
+        'side': 'sell',
+        'pair': 'mocked',
+        'datetime': arrow.utcnow().isoformat(),
+        'price': 0.00004173,
+        'amount': 91.99181073,
+        'remaining': 0.0,
+        'status': 'closed'
+    }
+
+
 @pytest.fixture
 def limit_buy_order_old():
     return {
diff --git a/freqtrade/tests/test_persistence.py b/freqtrade/tests/test_persistence.py
--- a/freqtrade/tests/test_persistence.py
+++ b/freqtrade/tests/test_persistence.py
@@ -62,7 +62,7 @@ def test_init_dryrun_db(default_conf, mocker):
 
 
 @pytest.mark.usefixtures("init_persistence")
-def test_update_with_bittrex(limit_buy_order, limit_sell_order, fee):
+def test_update_with_bittrex(limit_buy_order, limit_sell_order, fee, caplog):
     """
     On this test we will buy and sell a crypto currency.
 
@@ -91,6 +91,7 @@ def test_update_with_bittrex(limit_buy_order, limit_sell_order, fee):
     """
 
     trade = Trade(
+        id=2,
         pair='ETH/BTC',
         stake_amount=0.001,
         fee_open=fee.return_value,
@@ -108,13 +109,53 @@ def test_update_with_bittrex(limit_buy_order, limit_sell_order, fee):
     assert trade.open_rate == 0.00001099
     assert trade.close_profit is None
     assert trade.close_date is None
+    assert log_has("LIMIT_BUY has been fulfilled for Trade(id=2, "
+                   "pair=ETH/BTC, amount=90.99181073, open_rate=0.00001099, open_since=closed).",
+                   caplog.record_tuples)
 
+    caplog.clear()
     trade.open_order_id = 'something'
     trade.update(limit_sell_order)
     assert trade.open_order_id is None
     assert trade.close_rate == 0.00001173
     assert trade.close_profit == 0.06201058
     assert trade.close_date is not None
+    assert log_has("LIMIT_SELL has been fulfilled for Trade(id=2, "
+                   "pair=ETH/BTC, amount=90.99181073, open_rate=0.00001099, open_since=closed).",
+                   caplog.record_tuples)
+
+
+@pytest.mark.usefixtures("init_persistence")
+def test_update_market_order(market_buy_order, market_sell_order, fee, caplog):
+    trade = Trade(
+        id=1,
+        pair='ETH/BTC',
+        stake_amount=0.001,
+        fee_open=fee.return_value,
+        fee_close=fee.return_value,
+        exchange='bittrex',
+    )
+
+    trade.open_order_id = 'something'
+    trade.update(market_buy_order)
+    assert trade.open_order_id is None
+    assert trade.open_rate == 0.00004099
+    assert trade.close_profit is None
+    assert trade.close_date is None
+    assert log_has("MARKET_BUY has been fulfilled for Trade(id=1, "
+                   "pair=ETH/BTC, amount=91.99181073, open_rate=0.00004099, open_since=closed).",
+                   caplog.record_tuples)
+
+    caplog.clear()
+    trade.open_order_id = 'something'
+    trade.update(market_sell_order)
+    assert trade.open_order_id is None
+    assert trade.close_rate == 0.00004173
+    assert trade.close_profit == 0.01297561
+    assert trade.close_date is not None
+    assert log_has("MARKET_SELL has been fulfilled for Trade(id=1, "
+                   "pair=ETH/BTC, amount=91.99181073, open_rate=0.00004099, open_since=closed).",
+                   caplog.record_tuples)
 
 
 @pytest.mark.usefixtures("init_persistence")