diff --git a/backtrader/feeds/ibdata.py b/backtrader/feeds/ibdata.py index 5a955c8a8..719afa74d 100644 --- a/backtrader/feeds/ibdata.py +++ b/backtrader/feeds/ibdata.py @@ -365,6 +365,7 @@ def start(self): else: self._state = self._ST_START # initial state for _load self._statelivereconn = False # if reconnecting in live state + self._subcription_valid = False # subscription state self._storedmsg = dict() # keep pending live message (under None) if not self.ib.connected(): @@ -410,7 +411,7 @@ def stop(self): def reqdata(self): '''request real-time data. checks cash vs non-cash) and param useRT''' - if self.contract is None: + if self.contract is None or self._subcription_valid: return if self._usertvol: @@ -418,6 +419,7 @@ def reqdata(self): else: self.qlive = self.ib.reqRealTimeBars(self.contract) + self._subcription_valid = True return self.qlive def canceldata(self): @@ -446,7 +448,7 @@ def _load(self): if True: return None - # Code invalidated until further checking is done + # Code invalidated until further checking is done if not self._statelivereconn: return None # indicate timeout situation @@ -473,6 +475,7 @@ def _load(self): continue # to reenter the loop and hit st_historback if msg is None: # Conn broken during historical/backfilling + self._subcription_valid = False self.put_notification(self.CONNBROKEN) # Try to reconnect if not self.ib.reconnect(resub=True): @@ -489,6 +492,7 @@ def _load(self): elif msg == -1100: # conn broken # Tell to wait for a message to do a backfill # self._state = self._ST_DISCONN + self._subcription_valid = False self._statelivereconn = self.p.backfill continue @@ -500,6 +504,14 @@ def _load(self): elif msg == -1101: # conn broken/restored tickerId gone # The message may be duplicated + self._subcription_valid = False + if not self._statelivereconn: + self._statelivereconn = self.p.backfill + self.reqdata() # resubscribe + continue + + elif msg == -10225: # Bust event occurred, current subscription is deactivated. + self._subcription_valid = False if not self._statelivereconn: self._statelivereconn = self.p.backfill self.reqdata() # resubscribe @@ -561,14 +573,17 @@ def _load(self): msg = self.qhist.get() if msg is None: # Conn broken during historical/backfilling # Situation not managed. Simply bail out + self._subcription_valid = False self.put_notification(self.DISCONNECTED) return False # error management cancelled the queue elif msg == -354: # Data not subscribed + self._subcription_valid = False self.put_notification(self.NOTSUBSCRIBED) return False elif msg == -420: # No permissions for the data + self._subcription_valid = False self.put_notification(self.NOTSUBSCRIBED) return False diff --git a/backtrader/stores/ibstore.py b/backtrader/stores/ibstore.py index 5050b14c4..67c46446c 100644 --- a/backtrader/stores/ibstore.py +++ b/backtrader/stores/ibstore.py @@ -480,6 +480,16 @@ def error(self, msg): q.put(-msg.errorCode) self.cancelQueue(q) + elif msg.errorCode == 10225: + # 10225-Bust event occurred, current subscription is deactivated. + # Please resubscribe real-time bars immediately. + try: + q = self.qs[msg.id] + except KeyError: + pass # should not happend but it can + else: + q.put(-msg.errorCode) + elif msg.errorCode == 326: # not recoverable, clientId in use self.dontreconnect = True self.conn.disconnect()