Skip to content

Commit 49789e9

Browse files
committed
Merge remote-tracking branch 'robcarver17/develop' into missing-data-4
2 parents 1b86b8d + bc535c5 commit 49789e9

File tree

6 files changed

+97
-40
lines changed

6 files changed

+97
-40
lines changed

sysbrokers/IB/client/ib_client.py

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
IBInstrumentIdentity,
1212
)
1313

14-
from syscore.constants import arg_not_supplied
14+
from syscore.constants import arg_not_supplied, missing_contract
1515
from syscore.cache import Cache
1616
from syscore.exceptions import missingContract
1717

@@ -103,7 +103,7 @@ def log(self):
103103
return self._log
104104

105105
def error_handler(
106-
self, reqid: int, error_code: int, error_string: str, contract: ibContract
106+
self, reqid: int, error_code: int, error_string: str, ib_contract: ibContract
107107
):
108108
"""
109109
Error handler called from server
@@ -116,32 +116,22 @@ def error_handler(
116116
:return: success
117117
"""
118118

119-
msg = "Reqid %d: %d %s" % (reqid, error_code, error_string)
120-
121-
log_to_use = self._get_log_for_contract(contract)
119+
msg = "Reqid %d: %d %s for %s" % (
120+
reqid,
121+
error_code,
122+
error_string,
123+
str(ib_contract),
124+
)
122125

123126
iserror = error_code in IB_IS_ERROR
124127
if iserror:
125128
# Serious requires some action
126129
myerror_type = IB_ERROR_TYPES.get(error_code, "generic")
127-
self.broker_error(msg=msg, myerror_type=myerror_type, log=log_to_use)
130+
self.broker_error(msg=msg, myerror_type=myerror_type, log=self.log)
128131

129132
else:
130133
# just a general message
131-
self.broker_message(msg=msg, log=log_to_use)
132-
133-
def _get_log_for_contract(self, contract: ibContract) -> pst_logger:
134-
if contract is None:
135-
log_to_use = self.log.setup()
136-
else:
137-
ib_expiry_str = contract.lastTradeDateOrContractMonth
138-
instrument_code = self.get_instrument_code_from_broker_contract_object(
139-
contract
140-
)
141-
futures_contract = futuresContract(instrument_code, ib_expiry_str)
142-
log_to_use = futures_contract.specific_log(self.log)
143-
144-
return log_to_use
134+
self.broker_message(msg=msg, log=self.log)
145135

146136
def broker_error(self, msg, log, myerror_type):
147137
log.warn(msg)
@@ -205,6 +195,7 @@ def broker_identity_for_contract(
205195
ib_code=str(contract_details.contract.symbol),
206196
ib_multiplier=float(contract_details.contract.multiplier),
207197
ib_exchange=str(contract_details.contract.exchange),
198+
ib_valid_exchange=str(contract_details.validExchanges),
208199
)
209200

210201
def get_contract_details(
@@ -214,7 +205,6 @@ def get_contract_details(
214205
allow_multiple_contracts: bool = False,
215206
) -> Union[ibContractDetails, List[ibContractDetails]]:
216207

217-
"""CACHING HERE CAUSES TOO MANY ERRORS SO DON'T USE IT"""
218208
contract_details = self._get_contract_details(
219209
ib_contract_pattern, allow_expired=allow_expired
220210
)
@@ -226,7 +216,9 @@ def get_contract_details(
226216
return contract_details
227217

228218
elif len(contract_details) > 1:
229-
self.log.critical("Multiple contracts and only expected one")
219+
self.log.critical(
220+
"Multiple contracts and only expected one - returning the first"
221+
)
230222

231223
return contract_details[0]
232224

sysbrokers/IB/client/ib_contracts_client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from copy import copy
22
from ib_insync import Contract
33

4+
from syscore.constants import missing_contract
45
from syscore.cache import Cache
56
from syscore.exceptions import missingData, missingContract
67
from sysbrokers.IB.client.ib_client import ibClient

sysbrokers/IB/config/ib_instrument_config.py

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
ibInstrumentConfigData,
88
)
99
from syscore.constants import missing_file, missing_instrument, arg_not_supplied
10+
from syscore.exceptions import missingData
1011
from syscore.fileutils import resolve_path_and_filename_for_package
1112
from syscore.genutils import return_another_value_if_nan
1213
from syslogdiag.log_to_screen import logtoscreen
@@ -104,6 +105,7 @@ class IBInstrumentIdentity:
104105
ib_code: str
105106
ib_multiplier: float
106107
ib_exchange: str
108+
ib_valid_exchange: str
107109

108110

109111
def get_instrument_code_from_broker_instrument_identity(
@@ -115,20 +117,35 @@ def get_instrument_code_from_broker_instrument_identity(
115117
ib_code = ib_instrument_identity.ib_code
116118
ib_multiplier = ib_instrument_identity.ib_multiplier
117119
ib_exchange = ib_instrument_identity.ib_exchange
120+
ib_valid_exchange = ib_instrument_identity.ib_valid_exchange
121+
122+
config_rows = _get_relevant_config_rows_from_broker_instrument_identity_fields(
123+
config=config,
124+
ib_code=ib_code,
125+
ib_multiplier=ib_multiplier,
126+
ib_exchange=ib_exchange,
127+
)
118128

119-
config_rows = config[
120-
(config.IBSymbol == ib_code)
121-
& (config.IBMultiplier == ib_multiplier)
122-
& (config.IBExchange == ib_exchange)
123-
]
124129
if len(config_rows) == 0:
125-
msg = "Broker symbol %s (%s, %f) not found in configuration file!" % (
126-
ib_code,
127-
ib_exchange,
128-
ib_multiplier,
129-
)
130-
log.critical(msg)
131-
raise Exception(msg)
130+
## try something else
131+
## might have a weird exchange, but the exchange we want is in validExchanges
132+
try:
133+
config_rows = _get_relevant_config_rows_from_broker_instrument_identity_using_multiple_valid_exchanges(
134+
config=config, ib_instrument_identity=ib_instrument_identity
135+
)
136+
137+
except:
138+
msg = (
139+
"Broker symbol %s (exchange:%s, valid_exchange:%s multiplier:%f) not found in configuration file!"
140+
% (
141+
ib_code,
142+
ib_exchange,
143+
ib_valid_exchange,
144+
ib_multiplier,
145+
)
146+
)
147+
log.critical(msg)
148+
raise Exception(msg)
132149

133150
if len(config_rows) > 1:
134151

@@ -142,6 +159,44 @@ def get_instrument_code_from_broker_instrument_identity(
142159
return config_rows.iloc[0].Instrument
143160

144161

162+
def _get_relevant_config_rows_from_broker_instrument_identity_using_multiple_valid_exchanges(
163+
config: IBconfig, ib_instrument_identity: IBInstrumentIdentity
164+
) -> pd.Series:
165+
166+
ib_code = ib_instrument_identity.ib_code
167+
ib_multiplier = ib_instrument_identity.ib_multiplier
168+
ib_valid_exchange = ib_instrument_identity.ib_valid_exchange
169+
170+
valid_exchanges = ib_valid_exchange.split(",")
171+
172+
for ib_exchange in valid_exchanges:
173+
config_rows = _get_relevant_config_rows_from_broker_instrument_identity_fields(
174+
config=config,
175+
ib_code=ib_code,
176+
ib_multiplier=ib_multiplier,
177+
ib_exchange=ib_exchange,
178+
)
179+
180+
if len(config_rows) == 1:
181+
## we have a match!
182+
return config_rows
183+
184+
raise missingData
185+
186+
187+
def _get_relevant_config_rows_from_broker_instrument_identity_fields(
188+
config: IBconfig, ib_code: str, ib_multiplier: float, ib_exchange: str
189+
) -> pd.Series:
190+
191+
config_rows = config[
192+
(config.IBSymbol == ib_code)
193+
& (config.IBMultiplier == ib_multiplier)
194+
& (config.IBExchange == ib_exchange)
195+
]
196+
197+
return config_rows
198+
199+
145200
def get_instrument_list_from_ib_config(
146201
config: IBconfig, log: pst_logger = logtoscreen("")
147202
):

sysbrokers/IB/ib_instruments_data.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from sysbrokers.IB.client.ib_client import ibClient
1414
from sysbrokers.broker_instrument_data import brokerFuturesInstrumentData
1515

16+
from syscore.constants import missing_contract
17+
from syscore.exceptions import missingContract
1618
from sysdata.data_blob import dataBlob
1719

1820
from syslogdiag.log_to_screen import logtoscreen
@@ -34,11 +36,17 @@ def __repr__(self):
3436
def get_instrument_code_from_broker_contract_object(
3537
self, broker_contract_object: ibContract
3638
) -> str:
37-
38-
return self.ib_client.get_instrument_code_from_broker_contract_object(
39-
broker_contract_object
39+
instrument_code = (
40+
self.ib_client.get_instrument_code_from_broker_contract_object(
41+
broker_contract_object
42+
)
4043
)
4144

45+
if instrument_code is missing_contract:
46+
raise missingContract
47+
48+
return instrument_code
49+
4250
def _get_instrument_data_without_checking(self, instrument_code: str):
4351
return self.get_futures_instrument_object_with_IB_data(instrument_code)
4452

syscore/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def __repr__(self):
1212
missing_instrument = named_object("missing instrument")
1313
missing_file = named_object("missing file")
1414
missing_data = named_object("missing data")
15+
missing_contract = named_object("missing contract")
1516
market_closed = named_object("market closed")
1617
fill_exceeds_trade = named_object("fill too big for trade")
1718
arg_not_supplied = named_object("arg not supplied")

sysdata/csv/csv_contract_position_data.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ def __repr__(self):
2929
return "csvContractPositionData accessing %s" % self._datapath
3030

3131
def _write_updated_position_series_for_contract_object(
32-
self, contract: futuresContract, update_series: pd.Series
32+
self, contract_object: futuresContract, updated_series: pd.Series
3333
):
34-
position_df = pd.DataFrame(update_series)
35-
filename = self._filename_given_contract(contract)
34+
position_df = pd.DataFrame(updated_series)
35+
filename = self._filename_given_contract(contract_object)
3636
position_df.to_csv(filename, index_label=DATE_INDEX_NAME)
3737

3838
def _filename_given_contract(self, contract: futuresContract):

0 commit comments

Comments
 (0)