ccxt: Order Cache falling out of sync, Poloniex
- OS: macOS 10.13.1
- Programming Language version: Python 2.7.14
- CCXT version: 1.10.981
- Exchange: Poloniex
- Method:
fetchOrders
First, thanks for working on such a fantastic library. Really. š„. This is more of a question about best practices and less of an issue/bug.
Looking through the issue history, it looks like users often raise issues related to order fetching, and it looks like the culprit is almost always the order cache. Source:
Iāve been running into an issue with my Poloniex trades where fetchOrders will occasionally incorrectly return an order as completed and filled even though it was not. For example:
{āstatusā: āclosedā, āinfoā: {āstatusā: āopenā, uāorderNumberā: uā414719023990ā, uātypeā: ālimitā, āpriceā: uā0.09735495ā, uārateā: uā0.09735495ā, uāamountā: uā0.89599150ā, uādateā: uā2018-02-06 10:33:59ā, uātotalā: uā0.08722920ā, uāmarginā: 0, āsideā: uāsellā, uāstartingAmountā: uā0.89599150ā}, āfeeā: None, ātimestampā: 1517913239000, āpriceā: 0.09735495, ātradesā: None, āsideā: uāsellā, ādatetimeā: ā2018-02-06T10:33:59.000Zā, āsymbolā: uāETH/BTCā, āamountā: 0.8959915, ācostā: 0.087229207682925, ātypeā: ālimitā, āidā: uā414719023990ā, āfilledā: 0.8959915, āremainingā: 0.0}
When I go to the Poloniex Trade History on the site, there is no corresponding trade. Iām assuming what is happening here is the order is not found during the fetchOpenOrders call, and that results in the order in the cache being marked as 'closed', and the 'filled' attribute gets set equal to the 'amount' value. Looking back in my logs, I think this is the series of steps that results in this behavior:
cancelOrderresults in a request timeout.fetchOrdersreturns a list of orders that indicates the order is still open.cancelOrderresults in the āYou have already called cancelOrderā message from Poloniex.fetchOrdersreturns a list of orders that indicates the order is closed and has been filled.
Here are the corresponding logs I have for each step of 1-4.
poloniex POST https://poloniex.com/tradingApi request timeout poloniex POST https://poloniex.com/tradingApi request timeout- order extracted from list of all orders:
{'status': 'open', 'timestamp': 1517913239000, 'price': 0.09735495, 'datetime': '2018-02-06T10:33:59.000Z', 'cost': 0.0872292, 'id': u'414719023990', 'info': {'status': 'open', u'orderNumber': u'414719023990', u'type': 'limit', 'price': u'0.09735495', u'rate': u'0.09735495', u'amount': u'0.89599150', u'date': u'2018-02-06 10:33:59', u'total': u'0.08722920', u'margin': 0, 'side': u'sell', u'startingAmount': u'0.89599150'}, 'fee': None, 'trades': None, 'remaining': 0.8959915, 'symbol': u'ETH/BTC', 'amount': 0.8959915, 'type': 'limit', 'side': u'sell', 'filled': 0.0} poloniex {"error":"You have already called cancelOrder or moveOrder on this order. Please wait for that call's response."} poloniex {"error":"You have already called cancelOrder or moveOrder on this order. Please wait for that call's response."}- order extracted from list of all orders:
{'status': 'closed', 'info': {'status': 'open', u'orderNumber': u'414719023990', u'type': 'limit', 'price': u'0.09735495', u'rate': u'0.09735495', u'amount': u'0.89599150', u'date': u'2018-02-06 10:33:59', u'total': u'0.08722920', u'margin': 0, 'side': u'sell', u'startingAmount': u'0.89599150'}, 'fee': None, 'timestamp': 1517913239000, 'price': 0.09735495, 'trades': None, 'side': u'sell', 'datetime': '2018-02-06T10:33:59.000Z', 'symbol': u'ETH/BTC', 'amount': 0.8959915, 'cost': 0.087229207682925, 'type': 'limit', 'id': u'414719023990', 'filled': 0.8959915, 'remaining': 0.0}
As you can see in step 4, ccxt thinks the order has been filled.
Is there a best practice that I should follow that would circumvent this problem? Did the cache rework that I see referenced in 569 occur? If not, can I help with the cache rework?
Iām loving working with ccxt and again thanks for all your development effort, itās really appreciated.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 1
- Comments: 19 (11 by maintainers)
Commits related to this issue
- poloniex: cancelOrder: mark order as 'canceled' when cancellation request is pending (fixes #1801) — committed to mkutny/ccxt by mkutny 6 years ago
Thanks! A really nice-looking log, Iād put it as an example into āHow to submit an issueā section )
The issue is that itās got canceled on the exchange side, indeed. I added an explanation on how to handle
RequestTimeoutexceptions into the manual here: #1870. Iād like to know if you find it enough to answer your question or maybe you have a suggestion how to phrase it in a better language.Iāve upgraded to 1.10.1074 and Iām still hitting this bug. Here are my logs from most recent run showing where it occurred when a bid failed to cancel due to a request timeout.
This is without any cache reset on my part.
The Manual edits look good. Language is understandable. Thanks for taking the time to dive into this. Really appreciate it as well as everything you guys are doing.
Just to add-in an additional check here for anyone else who looks at this issue later on: in addition to re-trying
cancelOrderrequests you can also track your balance over time, and only honor filled orders if your balance changed nearby when that order was reported as filled. Both these solutions in tandem should be enough to ensure you donāt falsely act on an order being executed.Thanks again š
It will be fixed in #1849. Still, Iād appreciate if you could create an order, then send a non-blocking cancellation request and then tried to fetch order in
verbosemode. We know that Polo responds withpendingfor subsequent cancellation but I wonder what will it respond with on fetch.Right. It wonāt cause any harm now because in their current state neither Liqui nor Polo limit number of returned orders but we surely need to keep it in mind in case they start too.
Ok, I finally figured out whatās going on.
Youāre absolutely right! And it does related to cancelOrder.
So when you cancel an order and then you fetch (open) orders, the order is not in the cache indeed. So ccxt marks it as āclosedā although it was canceled in reality. It would be more appropriate to set the status to
undefinedbecause we really donāt know what happened to that order but I would be not quite comfortable with that.Looks like
cancelOrderneeds to catchCancelPendingexception and force update the cache.Iām going to have to wait until Binance trades are back up to report back on the impact of removing the cache reset.
Following up with @mkutny, I ran the following:
because I only had balance in ETH to test with, but it should map to your example (note I have here a buy and a sell vs two buys). Also, Iām not sure how youāre able to get your orders to go through with such low amounts and prices ā I always get an error indicating the trade amount must be larger, hence the different values Iām using here.
Output:
In my original examples I am calling fetchOrders by symbol, but all orders Iām placing or fetching fall under the same symbol. So Iām not sure whatever youāre bug youāre investigating over at #1830 is related.
This was worth mentioning from the very beginning, as this is most likely the reason for the inconsistencies above %)
Proper order caching relies on info in
.orders, so if you drop it regularly ā you will have a regular crash. It wasnāt designed to be dropped at all. You can probably safely remove the already-closed orders, if youāre not interested in them, but you canāt just setself.poloniex.orders = {}. The order cache is used to track order statuses, because Poloniex has a very poor API and doesnāt offer any endpoints for closed orders. The order cache is used to distinguish closed orders from remembered open orders. It is not the same as browser cache.Have you tried not resetting the cache?