The C++ API in IB may be structures differently (have not looked at your c++ code in detail) but the IsConnected method in c# is indeed utterly useless. One has to implement something on his one. Further how IB's API disconnects is a disgrace. Invoking disconnect basically throws errors because the socket is disconnected but the while loop that polls the socket is not exited. There are truly some very strange things the IB coders either don't understand, or did not have time to implement, or are incapable of implementing. No biggies for a capable coder to circumvent but true annoyances.
Are you using v9.72? I'm experiencing the same issue as described here in the API Yahoo group after moving from 9.71 to 9.72, which also sounds a lot like you describe when you say "Invoking disconnect basically throws errors because the socket is disconnected but the while loop that polls the socket is not exited." Can you share your fix or at least point to where this loop is so I can get a look at it? Thanks!
I don't have the code in front of me right now but you can either catch the error and handle it (which if memory serves was the proposed solution in the API Yahoo group, which by the way is the authority in anything IB API related), or else you can use the source code and replace some of the socket code with your own improved version. Downside of that is that you need to carry those changes over to each newly released API version. I myself ended up writing my own poller and that poller within a while loop exits as soon as the "Disconnect()" is invoked and only then will the socket be gracefully disconnected and closed and subsequently disposed. That is what worked for me.
Hi guys. Just wanted to contribute my workaround on this thread, since it appears it's the *only* one I could find about IB's API's lost-connection issue. I hope to save some other people some headache. And yes, the failure of .isConnected() has cost me 5-digit losses before. The workaround uses objEClientSocket.reqCurrentTime() to trigger a response at objEWrapper.currentTime(long time). The EWrapper then keeps track of the most-recent time returned by objEWrapper.currentTime(long time), and can return the number of seconds that has passed since the last full User -> TWS -> IB connection was made. For this, I extended EWrapper (to let's say, BenWrapper), and added the method: public long BenWrapper.getSecondsSinceLastContactWithTWSOrIB() {..return seconds since last contact here..} Then, the user's own connection poller repeatedly calls objEClientSocket.reqCurrentTime() at the poller's set interval, and at the same time, it checks how long a suspected disconnect has lasted (60secs? 90secs?,etc), and then force a reconnect via EClientSocket.eConnect(...) once that limit has passed. And so, my EWrapperAdapter.... Code: public class IBWrapperAdapter implements EWrapper { private long mostRecentTimeOfServerResponseInSec = System.currentTimeMillis()/1000L; ... /** * Returns the last time the TWS server could pull the time from IB's servers * via EClientSocket.reqCurrentTime(). * For this method to work as expected, the user must call EClientSocket.reqCurrentTime() * on a regular basis. This will act somewhat of a "heartbeat", to ensure a the * connection status of API -> TWS -> IB Servers. * @return */ public long getMostRecentTimeOfServerResponseInSec() { return this.mostRecentTimeOfServerResponseInSec; } public long getSecondsSinceLastContactWithTWSOrIB() { return System.currentTimeMillis()/1000L - this.getMostRecentTimeOfServerResponseInSec(); } public void resetSecondsSinceLastContactWithTWSOrIB() { this.mostRecentTimeOfServerResponseInSec = System.currentTimeMillis()/1000L; } ... } And the connection poller..... Code: private class TWSConnectionPoller implements Runnable { public TWSConnectionPoller() { } public void run() { // ibSocket.reqCurrentTime() lets IBWrapperAdapter know when the last // successful contact with IB's servers was. ibSocket.reqCurrentTime(); if (!ibSocket.isConnected()) { logger.info("Weird. Connection to TWS is disconnected."); /** * If we're going to reset this connection, we need a new ClientID */ twsClientID = new Random().nextInt(100000) * 10000 + 1; // ID used by TWS to identify this connection logger.info("Connecting to TWS on {} port {} with clientID {}", twsHost, twsHostPortNumber, twsClientID); ibSocket.eConnect(twsHost, twsHostPortNumber, twsClientID); if (!ibSocket.isConnected()) { logger.warn("TWSConnectionPoller couldn't reconnect to {} on port {}", twsHost, twsHostPortNumber); } else { logger.warn("Reconfirming all PricedAsset Positions"); reconfirmAllPricedAssetPositions(); } } long secondsSinceLastContact = objIBWrapperAdapter.getSecondsSinceLastContactWithTWSOrIB(); //System.out.println("Difference between now and last server contact is = " + secondsSinceLastContact + " seconds"); if (secondsSinceLastContact > 60) { // force the EClientSocket into a disconnected state, so the .isConnected() above will actually work. ibSocket.eDisconnect(); // reset the seconds counter to 0, so we'll try reconnecting (if still disconnected) in another 60 seconds. objIBWrapperAdapter.resetSecondsSinceLastContactWithTWSOrIB(); } } } Might not be as elegant as some other solutions, but the idea is simple enough to implement Hope this helps some people prevent some future losses.