diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index ff282aa77..c1a898c30 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -527,7 +527,7 @@ class FreqtradeBot: order = self.exchange.buy(pair=pair, ordertype=order_type, amount=amount, rate=buy_limit_requested, time_in_force=time_in_force) - order_obj = Order.parse_from_ccxt_object(order, pair) + order_obj = Order.parse_from_ccxt_object(order, 'buy') order_id = order['id'] order_status = order.get('status', None) @@ -784,7 +784,7 @@ class FreqtradeBot: stop_price=stop_price, order_types=self.strategy.order_types) - order_obj = Order.parse_from_ccxt_object(stoploss_order, trade.pair) + order_obj = Order.parse_from_ccxt_object(stoploss_order, 'stoploss') trade.orders.append(order_obj) trade.stoploss_order_id = str(stoploss_order['id']) return True @@ -1134,7 +1134,7 @@ class FreqtradeBot: time_in_force=time_in_force ) - order_obj = Order.parse_from_ccxt_object(order, trade.pair) + order_obj = Order.parse_from_ccxt_object(order, 'sell') trade.orders.append(order_obj) trade.open_order_id = order['id'] diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 3b77438ea..c50fcbe88 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -101,36 +101,49 @@ class Order(_DECL_BASE): id = Column(Integer, primary_key=True) trade_id = Column(Integer, ForeignKey('trades.id'), index=True) + ft_order_side = Column(String, nullable=False) + order_id = Column(String, nullable=False, index=True) - status = Column(String, nullable=False) - symbol = Column(String, nullable=False) - order_type = Column(String, nullable=False) - side = Column(String, nullable=False) - price = Column(Float, nullable=False) - amount = Column(Float, nullable=False) + status = Column(String, nullable=True) + symbol = Column(String, nullable=True) + order_type = Column(String, nullable=True) + side = Column(String, nullable=True) + price = Column(Float, nullable=True) + amount = Column(Float, nullable=True) filled = Column(Float, nullable=True) remaining = Column(Float, nullable=True) cost = Column(Float, nullable=True) order_date = Column(DateTime, nullable=False, default=datetime.utcnow) order_filled_date = Column(DateTime, nullable=True) + def update_from_ccxt_object(self, order): + """ + Update Order from ccxt response + Only updates if fields are available from ccxt - + """ + if self.order_id != str(order['id']): + return OperationalException("Order-id's don't match") + + self.status = order.get('status', self.status) + self.symbol = order.get('symbol', self.symbol) + self.order_type = order.get('type', self.order_type) + self.side = order.get('side', self.side) + self.price = order.get('price', self.price) + self.amount = order.get('amount', self.amount) + self.filled = order.get('filled', self.filled) + self.remaining = order.get('remaining', self.remaining) + self.cost = order.get('cost', self.cost) + if 'timestamp' in order and order['timestamp'] is not None: + self.order_date = datetime.fromtimestamp(order['timestamp']) + @staticmethod - def parse_from_ccxt_object(order, pair) -> 'Order': + def parse_from_ccxt_object(order: Dict[str, Any], side: str) -> 'Order': """ Parse an order from a ccxt object and return a new order Object. """ - o = Order(order_id=str(order['id'])) + o = Order(order_id=str(order['id']), ft_order_side=side) - o.status = order['status'] - o.symbol = order.get('symbol', pair) - o.order_type = order['type'] - o.side = order['side'] - o.price = order['price'] - o.amount = order['amount'] - o.filled = order.get('filled') - o.remaining = order.get('remaining') - o.cost = order.get('cost') - o.order_date = datetime.fromtimestamp(order['timestamp']) + o.update_from_ccxt_object(order) return o def __repr__(self): diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 40340fcd0..1621be6e5 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1313,7 +1313,7 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee, assert rpc_mock.call_args_list[1][0][0]['order_type'] == 'market' -def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, caplog, +def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, limit_buy_order, limit_sell_order) -> None: # When trailing stoploss is set stoploss = MagicMock(return_value={'id': 13434334}) @@ -1823,7 +1823,8 @@ def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_orde assert not trade.is_open -def test_handle_trade(default_conf, limit_buy_order, limit_sell_order_open, limit_sell_order, fee, mocker) -> None: +def test_handle_trade(default_conf, limit_buy_order, limit_sell_order_open, limit_sell_order, + fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -1863,7 +1864,8 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order_open, limi assert trade.close_date is not None -def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open, fee, mocker) -> None: +def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order_open, + fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple(