Keyboard Shortcuts
Likes
- Twsapi
- Messages
Search
Re: C++ preventing EReader reading when socket is closed
On Sun, Oct 1, 2023 at 03:15 PM, David Armour wrote:
You may see this as a wart but I, personally, won't comment with regard to how intuitive things are or any design aesthetic. I will say that consideration should be given to backward compatibility and just how much existing code would break (and therefore need to change) if the disconnect where removed from the destructor. Just some food for thought... since there's usually ripple effects, unintended consequences, and API stability is actually very important. Also, I don't think it's wise to hold off fixing some simple, obvious, and existing issue merely because there's an intention of addressing it in a more significant re-design. As they say, there is no time like the present and I appreciate small and tractable, incremental changes. However, this may come down to a judgment call. Since, I guess, people have indeed been ignoring it or working around it (or it's simply gone unnoticed). After all, it only happens late in the game when there usually isn't much network activity expected or necessarily happening.
A pull request is probably the best way to go about this: |
Re: C++ preventing EReader reading when socket is closed
I agree with everything you said although I am not entirely happy with my final solution. I do not feel that destroying the EReader object is the correct way to disconnect. It is certainly not intuitive which means I cannot be the only person finding this problem. Is everybody using C++ just ignoring this error?
Anyway, I will sleep on it one more night before submitting a bug report. Is there a special place to report API bugs or do we just raise ticket as usual? |
Re: C++ preventing EReader reading when socket is closed
On Sun, Oct 1, 2023 at 10:02 AM, David Armour wrote:
You're welcome. I think you've found an interesting oversight.
Yeah, superficially and at first blush it would seem that way. But it'd be a mistake to think so. I can understand how that initial thought may have fooled the original author into thinking the code was correct though. All this is post-mortem speculation on my part however. Nevertheless, once considered more thoughtfully, it becomes apparent that nothing prevents the destructor from being called while the processing thread's readToQueue is in the while block. The std::atomic will only insure that reading and writing m_isAlive from multiple threads is well-defined; but guarantees nothing w.r.t. the destructor and what's happening in the while loop.
"Pause", with a sleep or something? No... that's surely a game of whack-a-mole. It might work sometimes, depending on unpredictable factors, and might not. It can be fun to experiment with the timing while you investigate though. You can also try playing w/ ordering by running the code on a single core/cpu and see how that affects things.
Compiler optimizations fall somewhat into the category of "unpredictable factors" I alluded to (although they'd be deterministic given the compiler source and enough work). It's a bit surprising that a critical section wasn't implemented via mutex, but maybe the author wanted to avoid a performance penalty.
Anyway... I think you found a legitimate problem and I wouldn't worry about it too much. I like your proposed solution as well. Joining the thread and then disconnecting makes clear sense to me. And, as long as m_pClientSocket isn't being shared all over the place I don't see a reason to use more complicated locking via mutex. If I were the reviewer I could see signing off after some confirmation tests... open a ticket and see what they have to say. If you submit a patch remember to change the IB_POSIX ifdef block too :-) |
Re: C++ preventing EReader reading when socket is closed
Thanks for your comment Buddy.
I agree that the logic would seem that setting m_isAlive to false during the ~EReader() call should prevent the code trying to read from the socket. I tried playing around with that. If I pause after m_isAlive is set to false, then continue, the code works successfully without 509 error. It is as if at full speed the atomic operation is not being completed before the call to eDisconnect() happens. On Visual Studio this even happens when I turn off all Optimisations. As eDisconnect() does not use anything related to that atomic, I wonder if the compiler is parallelising the operation as all atomic operations are very slow. I also noticed that eDisconnect() sets m_fd = -1.? This should prevent the call to processNonBlockingSelect() from trying to call onReceive() which ultimately triggers receive() and recv() causing the error. Again the setting of the atomic variable is not being done in time. I am still scratching my head over this. I suspect some synchronization issue between the various threads. |
Re: C++ preventing EReader reading when socket is closed
I guess the assumption is that using
But it does not, so I take your point. |
Re: C++ preventing EReader reading when socket is closed
After much deliberation, I think I figured out the problem.
In my opinion it is a bug in the TWS API for C++. I would like someone's help to go thru' my logic and confirm it. The EReader::~EReader() destructor closes the socket by calling eDisconnect() then it waits for the thread to complete by calling WaitForSingleObject(m_hReadThread, INFINITE); In my opinion this is wrong. Why would you want to disconnect the socket when you have a thread running which is potentially calling recv() on the same socket? In my view, we have to wait for the thread to finish then disconnect the socket. My fix to the problem is to swap the two steps, i.e. ??? if (m_hReadThread) {becomes ??? if (m_hReadThread) { This has resolved the issue. Could someone confirm my logic so I can issue a bug report to the IBKR guys? Thanks |
C++ preventing EReader reading when socket is closed
I have faced a problem with my code for a long time that only occurs during the call to EClientSocket::eDisconnect()
I have a separate message processing thread running which looks like this: ????? ftrMsgProcThrd_ = pool_->submit( I decided to tackle this annoying bug (not the first time) and have found that after the call to EClientSocket::eDisconnect() which calls EClientSocket::SocketClose() which just calls a Windows Sockets closesocket() on the open socket, I am still getting the message processing thread (EReader thread) trying to perform a Windows Sockets recv() messages on the closed socket resulting in a 509 error. I have traced that error to be socket error 10038 which confirms it is an invalid socket (in this case, a closed socket). |
Re: TWS api multiple similar orders submission delays
"200ms-400ms? delay in between each order is transmitted by Gateway and has?Submitted status"Do you wait for the "Submit" status before submitting your next order? Can you submit orders without waiting for the status update? How do you measure time? I placed 8 orders (3 bracket orders) for 8 different stocks and the avg time per stock (i.e. 8 orders) was 3 msecs. I have seen some stocks (e.g. NFLX) take 5-8 msecs. I do not wait for the submit status, and by the time I am done placing 64 orders, avg of ~25 msecs have passed (and this includes time from TWS callbacks and my own logic). Not sure how much difference does it make but I tested with very liquid US stks, am using C++ and TWS GUI, tested within 1/2 hour of market open.? |
Re: IB's own SAMPLE Excel files still refer to de-supported order attributes so they don't work at all -- how do I bypass / fix??
Thank you for taking the time to step through the VBA code. If I'm understanding correctly, you're saying that the problem exists in the separate ddedll.dll library file, which is a black box / unmodifiable by the end user?
As for TWS / API versioning, I'm using:
They've acknowledged that the 3 order attributes were indeed desupported in API v 10.10 (as documented here:?), but the Q I can't get to the bottom of is what is it about the LegacyTwsDde.xls Sample file that's generate the NbboPriceCap error and preventing orders from getting placed? Like it's all fine and well to "de-support" order attributes, but could it simply be the case that the developers forgot to update the LegacyTwsDde Sample file, which is coded in such a way as to be submitting orders with 3 order attributes that no longer exist, and so something in the chain from Excel > API > TWS is flat-out rejecting these orders as containing, essentially, 'gibberish'? And -- if I'm understanding correctly -- there's nothing that I as the end user can easily modify in the Sample file's VBA to simply not include these now-desupported attributes? (And if that's true then...just?where/when are these attributes getting instructed?) These all seem like issues IB's API team should understand immediately, but...well, I'm here trying to diagnose from afar because I haven't been making any progress with them. |
Re: did something change on 9/21/22 getting 366 on a feed that "WAS" working well.
闯ü谤驳别苍 wrote: "TWS/IBGW actually memorizes the highest orderId for each clientId and each account. I did not know this either for the longest time, but I think it was JG who made a comment related to this in a post a couple months ago."
Your memory has not failed you: it was indeed me who wrote on a few occasions that TWS/IBGW memorizes the highest orderId for each clientId. |
Re: did something change on 9/21/22 getting 366 on a feed that "WAS" working well.
@Richard I know that you were not trying to suggest one should use the same numerical ids for different request types. I just wanted to add another reason why one should not do it. Looks like we "late comers" have a little advantage since the TWS API source code contains more useful bits than what you had to work with in the early years. @Gordon We are meandering away from the original topic, but a couple thoughts on why you get "117" or something similar for nextValidId. TWS/IBGW actually memorizes the highest orderId for each clientId and each account. I did not know this either for the longest time, but I think it was JG who made a comment related to this in a post a couple months ago. So I went through the logs and looked for the oldest clientId I could find for a client that placed orders (that clientId had not been used in at least three years), used that clientId to connect to the account, and for sure, automagically, nextOrderId upon connection returned a number that was one higher than the last order that client had placed three years ago. So if you are reusing the same clientId and that client occasionally places orders, nextOrderId will be going up slightly over time. I guess the clientId that gave you a nextValidId of "117" has placed 115 or so orders over time. You can break that cycle and reset all orderIds for all clientIds for an account back to, I believe, "1" with the "Reset API order ID sequence" button at the bottom of "Global Configuration -> Configuration -> API -> Settings". We also never call reqIds while a client is running. The nextValidId we receive as part of the connection protocol is sufficient for a sequence of (thread safe) incrementing orderIds. We recently added a little code that potentially nudges the clients' internal nextValidOrderId counter while they are running. That code assures that the nextValidOrderId counter is always higher than any orderId the client is exposed to by openOrder and orderStatus callbacks. This is most important for the master client and client 0 but we just added it to the framework for all clients based on this comment in : "However if there are multiple client applications connected to one account, it is necessary to use an order ID with new orders which is greater than all previous order IDs returned to the client application in openOrder or orderStatus callbacks." 闯ü谤驳别苍 On Thu, Sep 28, 2023 at 03:00 PM, Gordon Eldest wrote:
|
Erratic results from live data requests
I request live data with generic ticks set to RT Trade Volume (#375) which returns a trade volume string in addition to the regular default tick data (bid, ask, size etc).? ?Lately I've been getting erratic results where all the default tick data is missing and only the trade volume string is returned.? Sometimes the request works correctly but other times the exact same request will be missing the default data.? The data is missing from the API logs too.
I've tried restarting the Gateway when this happens but I'm not sure that's helping.?? Anyone have any suggestions? |
Re: did something change on 9/21/22 getting 366 on a feed that "WAS" working well.
I never got a first nextValidID? < 100.? |
Re: did something change on 9/21/22 getting 366 on a feed that "WAS" working well.
开云体育thank you for the clarification. Gives me a better handle on what's going on. I'm going to rationalize my data approach in 2024 as I have MANY experimental scripts ( python, julia, and now mojo) which are run by cron jobs. I just shut one down that's been running for 2 years and there's a 20gb csv with all the data.? Thanks again for all you do and taking the time.
On 9/28/23 14:33, 闯ü谤驳别苍 Reinold via
groups.io wrote:
|
Re: did something change on 9/21/22 getting 366 on a feed that "WAS" working well.
Good luck with log reading. I hope it helps you find the root cause. I removed lots of log detail in the hope that would make things clearer, but apparently it did not. To summarize the log one more time:
Since you push the envelope a little by requesting historical data for 100 instruments I thought it might be good to make sure the client is careful with other requests that inadvertently cause HMDS queries. 闯ü谤驳别苍 On Thu, Sep 28, 2023 at 02:16 PM, dent wrote:
|
Re: did something change on 9/21/22 getting 366 on a feed that "WAS" working well.
开云体育thank you AGAIN for such a detailed analysis.? I have turned on the HMDS logging feature for extra detail, thanks again for the heads up.? I am always a little nervous when there is a hint of data flow consolidation. I can see why they would want to do it but... the issue I have with these logs is that I would have expected the log to show the unique identifiers for the request. Your request reqMktData( ADS:STK:FWB )? has no, that I can see, identifier NOR does the log give me a CLEAR indication of which dataserver got the request. I understand that they have load balancers but it would be nice to be able to read the logs more clearly. I had not thought to look at the internal TWS logs partly because
I don't like having to decrypt them all the time. I hoped that I
could turn encryption off but I suppose that it's necessary in
this day and age. Based on your wonderful ( as always) overview I am going through all my linux boxes ( scattered over the house) and check the crontab for TWS scripts that might be running that add to my data pacing. I'm decrypting an api log now so I'll try to figure out what's going on. I am not a fan of the TWS log encryption preferring straightforward text so I can ssh into the tws machine and work that way. thanks again for EVERYTHING you do.
On 9/28/23 13:52, 闯ü谤驳别苍 Reinold via
groups.io wrote:
|
Re: did something change on 9/21/22 getting 366 on a feed that "WAS" working well.
You are welcome. Generally, IBKR has relaxed historical data pacing rules over the years, but in the spirit of "did something change", here a couple of observations. This is "thin ice territory" in the sense that I'll describe some observations but I have no more insight into or documentation for what is really going on. During the transition from V9 to V10 TWS/IBGW we detected that Historical Market Data Servers (HMDS farms) had become more prominent and that they must have taken on functions other than simply providing historical market data. They may had been involved before, but as part of our V10 testing and qualification they stood out. Also, TWS/IBGW suddenly had the HMDS logging feature that gives great insight into the kinds of XML database queries TWS/IBGW send to the various HMDS farms. HMDS and market data farms in each region seem to be responsible for contract related details, real time data, and historical data for the instruments traded in that region. Below a log overview for an attempt to get real-time market data for a Frankfurt FWB traded instrument that we do not have a market data subscription for. You see that our TWS was connected to usfuture.nj, usfuture, usfarm, ushmds, and secdefnj at the moment our client started and that euhmds and eufarm were temporarily connected once we made the call. They were automatically disconnected after 3 minutes of inactivity. This may be relevant to your problem since most (all ?) HMDS queries trugered by your clients' requests (not just calls) seem to count somehow towards historical market data pacing. At least for TWS around V10.10? to V10.12 when we did our tests. The funny thing was that we got unexplained TWSAPI errors (similar to your 366) that did not say "pacing violation" in the error message but the corresponding TWS HMDS internal logs clearly did. We restructured the tool that caused the errors, removed calls to that we really did not need (they caused HMDS queries) and the errors when away. So I guess this was the long way of saying that the combined requests your client sends to TWS/IBGW may trigger a silent pacing violation that leads to error 366 "ticker id was cancelled" situations. After all, you said you make requests for 100 instruments. Just a thought, 闯ü谤驳别苍=== 12:31.13 === Connect to TWS reqError code=2104 msg=Market data farm connection is OK:usfuture.nj reqError code=2104 msg=Market data farm connection is OK:usfuture reqError code=2104 msg=Market data farm connection is OK:usfarm reqError code=2106 msg=HMDS data farm connection is OK:ushmds reqError code=2158 msg=Sec-def data farm connection is OK:secdefnj reqContractDetails for ADS:STK:FWB reqMktData( ADS:STK:FWB ) reqError code=2106 msg=HMDS data farm connection is OK:euhmds reqError code=2104 msg=Market data farm connection is OK:eufarm tickReqParams[ADS] minTick 0.0 bboExchange 250001 snapshotPermissions 4 reqError code=354 msg=Requested market data is not subscribed.Delayed market data is not available.ADS IBIS/TOP/ALL === 12:31:16.488 === Conection stays active by no more API requests or responses === 12:34:52.270 === reqError code=2108 msg=Market data farm connection is inactive but should be available upon demand.eufarm === 12:34:52.346 === reqError code=2108 msg=Market data farm connection is inactive but should be available upon demand.eufarm On Thu, Sep 28, 2023 at 10:21 AM, dent wrote:
|
Re: did something change on 9/21/22 getting 366 on a feed that "WAS" working well.
开云体育闯ü谤驳别苍 ? I wasn’t trying to suggest that one should use the same order ids for different request types, merely that the rules are far more relaxed than Gordon’s post implied. ? Indeed, what I’ve been doing in my own platform since 10 March 2006 (according to my source control repository) is to use different ranges of ids for different classes of requests (not simply distinguishing between order ids and all other ids). Apart from simplifying error handling (which was indeed the initial impetus for doing this), it is also helpful in the next layer up from the component that implements the TWSAPI. ? I think that somewhat predates IB’s ApiController class! The latter is from May 2013 in TWS API v9.70.. ? Richard |
Re: did something change on 9/21/22 getting 366 on a feed that "WAS" working well.
开云体育WOW that's my bad sorry. the last date the program worked was Thu
21 Sep 2023 02:11:09 AM then the next day Fri 22 Sep 2023
02:11:09 AM CDT? it failed to get any data.? Excellent work Holmes
:-)?
On 9/28/23 10:40, J G via groups.io
wrote:
comicpilsen, I see you consistently mentioning the date to be 9/20/22. Are you sure that you stopped getting data one year ago? Or am I misunderstanding what the issue is? |