Skip to content

Commit 3fdd153

Browse files
author
rob
committed
reinstate caching and fix up methods
1 parent ca9c119 commit 3fdd153

11 files changed

+100
-136
lines changed

docs/IB.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ ib_futures_instrument_data = ibFuturesInstrumentData(conn)
188188
ib_futures_instrument_data.get_list_of_instruments()
189189
ib_futures_instrument_data.get_futures_instrument_object_with_IB_data("EDOLLAR") # again used by other functions to get the 'metadata' to map into IB instruments
190190
ib_futures_instrument_data.get_brokers_instrument_code("EDOLLAR") # reverse of next function
191-
ib_futures_instrument_data.get_instrument_code_from_broker_code("GE") # reverse of previous function
191+
ib_futures_instrument_data.get_instrument_code_from_broker_contract_object("GE") # reverse of previous function
192192
```
193193

194194

sysbrokers/IB/client/ib_client.py

+49-37
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import datetime
2-
from typing import Tuple
2+
from typing import Tuple, List
33
from ib_insync import IB
44

55
from sysbrokers.IB.ib_connection import connectionIB
6-
from sysbrokers.IB.ib_contracts import ibContract
6+
from sysbrokers.IB.ib_contracts import ibContract, ibContractDetails
77
from sysbrokers.IB.config.ib_instrument_config import (
88
IBconfig,
99
read_ib_config_from_file,
10-
get_instrument_code_from_broker_code,
10+
get_instrument_code_from_broker_instrument_identity,
11+
IBInstrumentIdentity,
1112
)
1213

1314
from syscore.constants import arg_not_supplied
@@ -133,21 +134,10 @@ def _get_log_for_contract(self, contract: ibContract) -> logger:
133134
if contract is None:
134135
log_to_use = self.log.setup()
135136
else:
136-
ib_instrument_code = contract.symbol
137137
ib_expiry_str = contract.lastTradeDateOrContractMonth
138-
139-
contract_details = self.contract_details(
140-
contract, allow_expired=False, allow_multiple_contracts=False
141-
)
142-
143-
## FIXME: REPLACE WITH GET EXTENDED CONTRACT DETAILS?
144-
ib_exchange = arg_not_supplied
145-
ib_multiplier = arg_not_supplied
146-
147-
instrument_code = self.get_instrument_code_from_broker_code(
148-
ib_instrument_code
138+
instrument_code = self.get_instrument_code_from_broker_contract_object(
139+
contract
149140
)
150-
151141
futures_contract = futuresContract(instrument_code, ib_expiry_str)
152142
log_to_use = futures_contract.specific_log(self.log)
153143

@@ -162,18 +152,27 @@ def broker_message(self, log, msg):
162152
def refresh(self):
163153
self.ib.sleep(0.00001)
164154

165-
def get_instrument_code_from_broker_code(
166-
self,
167-
ib_code: str,
168-
ib_multiplier: float = arg_not_supplied,
169-
ib_exchange: str = arg_not_supplied,
155+
def get_instrument_code_from_broker_contract_object(
156+
self, broker_contract_object: ibContract
170157
) -> str:
171-
instrument_code = get_instrument_code_from_broker_code(
158+
159+
broker_identity = self.broker_identity_for_contract(broker_contract_object)
160+
instrument_code = self.get_instrument_code_from_broker_identity_for_contract(
161+
broker_identity
162+
)
163+
164+
return instrument_code
165+
166+
def get_instrument_code_from_broker_identity_for_contract(
167+
self, ib_instrument_identity: IBInstrumentIdentity, config=arg_not_supplied
168+
) -> str:
169+
if config is arg_not_supplied:
170+
config = self.ib_config
171+
172+
instrument_code = get_instrument_code_from_broker_instrument_identity(
173+
ib_instrument_identity=ib_instrument_identity,
172174
log=self.log,
173-
ib_code=ib_code,
174-
config=self.ib_config,
175-
ib_multiplier=ib_multiplier,
176-
ib_exchange=ib_exchange,
175+
config=config,
177176
)
178177
return instrument_code
179178

@@ -191,19 +190,32 @@ def _get_and_set_ib_config_from_file(self) -> IBconfig:
191190

192191
return config_data
193192

194-
def contract_details(
193+
def broker_identity_for_contract(
194+
self,
195+
ib_contract_pattern: ibContract,
196+
) -> IBInstrumentIdentity:
197+
198+
contract_details = self.get_contract_details(
199+
ib_contract_pattern=ib_contract_pattern,
200+
allow_expired=False,
201+
allow_multiple_contracts=False,
202+
)
203+
204+
return IBInstrumentIdentity(
205+
ib_code=contract_details.contract.symbol,
206+
ib_multiplier=contract_details.contract.multiplier,
207+
ib_exchange=contract_details.contract.exchange,
208+
)
209+
210+
def get_contract_details(
195211
self,
196212
ib_contract_pattern: ibContract,
197213
allow_expired: bool = False,
198214
allow_multiple_contracts: bool = False,
199-
) -> Tuple[ibContract, list]:
200-
201-
# contract_details = self.cache.get(
202-
# self._contract_details, ib_contract_pattern, allow_expired=allow_expired
203-
# )
204-
# FIXME TRY WITHOUT CACHING FOR NOW
205-
contract_details = self._contract_details(
206-
ib_contract_pattern, allow_expired=allow_expired
215+
) -> Tuple[ibContractDetails, List[ibContractDetails]]:
216+
217+
contract_details = self.cache.get(
218+
self._get_contract_details, ib_contract_pattern, allow_expired=allow_expired
207219
)
208220

209221
if len(contract_details) == 0:
@@ -217,9 +229,9 @@ def contract_details(
217229

218230
return contract_details[0]
219231

220-
def _contract_details(
232+
def _get_contract_details(
221233
self, ib_contract_pattern: ibContract, allow_expired: bool = False
222-
) -> list:
234+
) -> List[ibContractDetails]:
223235
ib_contract_pattern.includeExpired = allow_expired
224236

225237
return self.ib.reqContractDetails(ib_contract_pattern)

sysbrokers/IB/client/ib_contracts_client.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ def ib_get_contract_chain(
589589
:return: list of ibContracts
590590
"""
591591

592-
new_contract_details_list = self.contract_details(
592+
new_contract_details_list = self.get_contract_details(
593593
ibcontract_pattern,
594594
allow_expired=allow_expired,
595595
allow_multiple_contracts=True,

sysbrokers/IB/client/ib_positions_client.py

+1-33
Original file line numberDiff line numberDiff line change
@@ -18,40 +18,8 @@ def broker_get_positions(
1818
# contract expiry
1919

2020
list_of_raw_positions = self.ib.positions()
21-
raw_positions_with_codes = self.add_exchange_codes_to_list_of_raw_ib_positions(
22-
list_of_raw_positions
23-
)
2421
dict_of_positions = from_ib_positions_to_dict(
25-
raw_positions_with_codes, account_id=account_id
22+
list_of_raw_positions, account_id=account_id
2623
)
2724

2825
return dict_of_positions
29-
30-
def add_exchange_codes_to_list_of_raw_ib_positions(
31-
self, list_of_raw_positions: list
32-
) -> list:
33-
raw_positions_with_codes = [
34-
self.add_exchange_code_to_raw_ib_position(raw_position)
35-
for raw_position in list_of_raw_positions
36-
]
37-
38-
return raw_positions_with_codes
39-
40-
def add_exchange_code_to_raw_ib_position(
41-
self, raw_ib_position: Position
42-
) -> IBPositionWithExtendedAttr:
43-
try:
44-
ib_contract = raw_ib_position.contract
45-
list_of_contract_details = self.ib.reqContractDetails(ib_contract)
46-
if len(list_of_contract_details) > 1:
47-
self.log.critical("Position should only have one contract associated")
48-
contract_details = list_of_contract_details[0]
49-
exchange_code = contract_details.validExchanges
50-
except:
51-
exchange_code = ""
52-
53-
new_ib_position = IBPositionWithExtendedAttr.from_ib_position(
54-
ib_position=raw_ib_position, exchange=exchange_code
55-
)
56-
57-
return new_ib_position

sysbrokers/IB/config/ib_instrument_config.py

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from dataclasses import dataclass
12
import pandas as pd
23

34
from sysbrokers.IB.ib_instruments import (
@@ -98,14 +99,20 @@ def _get_instrument_object_from_valid_config(
9899
return futures_instrument_with_ib_data
99100

100101

101-
def get_instrument_code_from_broker_code(
102+
@dataclass
103+
class IBInstrumentIdentity:
104+
ib_code: str
105+
ib_multiplier: float
106+
ib_exchange: str
107+
108+
109+
def get_instrument_code_from_broker_instrument_identity(
102110
config: IBconfig,
103-
ib_code: str,
111+
ib_instrument_identity: IBInstrumentIdentity,
104112
log: logger = logtoscreen(""),
105-
ib_exchange: str = arg_not_supplied,
106-
ib_multiplier: float = arg_not_supplied,
107113
) -> str:
108114

115+
ib_code = ib_instrument_identity.ib_code
109116
config_row = config[config.IBSymbol == ib_code]
110117
if len(config_row) == 0:
111118
msg = "Broker symbol %s not found in configuration file!" % ib_code
@@ -116,11 +123,9 @@ def get_instrument_code_from_broker_code(
116123
## need to resolve with multiplier
117124
instrument_code = (
118125
get_instrument_code_from_broker_code_with_multiple_possibilities(
119-
ib_code=ib_code,
126+
ib_instrument_identity=ib_instrument_identity,
120127
config=config,
121128
log=log,
122-
ib_exchange=ib_exchange,
123-
ib_multiplier=ib_multiplier,
124129
)
125130
)
126131
else:
@@ -130,13 +135,11 @@ def get_instrument_code_from_broker_code(
130135

131136

132137
def get_instrument_code_from_broker_code_with_multiple_possibilities(
138+
ib_instrument_identity: IBInstrumentIdentity,
133139
config: IBconfig,
134-
ib_code: str,
135140
log: logger = logtoscreen(""),
136-
ib_exchange: str = arg_not_supplied,
137-
ib_multiplier: float = arg_not_supplied,
138141
) -> str:
139-
142+
ib_code = ib_instrument_identity.ib_code
140143
# FIXME PATCH
141144
if ib_code == "EOE":
142145
return "AEX"

sysbrokers/IB/ib_contract_position_data.py

+3-7
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,9 @@ def _get_contract_position_for_raw_entry(self, position_entry) -> contractPositi
9191

9292
def _get_instrument_code_from_ib_position_entry(self, position_entry) -> str:
9393

94-
ib_code = position_entry["symbol"]
95-
ib_multiplier = position_entry["multiplier"]
96-
ib_exchange = position_entry["exchange"]
97-
instrument_code = (
98-
self.futures_instrument_data.get_instrument_code_from_broker_code(
99-
ib_code, ib_exchange=ib_exchange, ib_multiplier=ib_multiplier
100-
)
94+
ib_contract = position_entry.ib_contract
95+
instrument_code = self.futures_instrument_data.get_instrument_code_from_broker_contract_object(
96+
ib_contract
10197
)
10298

10399
return instrument_code

sysbrokers/IB/ib_contracts.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from ib_insync import Contract as ibContract, Contract, ComboLeg
2+
23
import re
34

45
from sysbrokers.IB.ib_instruments import (

sysbrokers/IB/ib_instruments_data.py

+22-30
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,42 @@
22
IBconfig,
33
read_ib_config_from_file,
44
get_instrument_object_from_config,
5-
get_instrument_code_from_broker_code,
65
IB_FUTURES_CONFIG_FILE,
76
get_instrument_list_from_ib_config,
87
)
98
from sysbrokers.IB.ib_instruments import (
109
futuresInstrumentWithIBConfigData,
1110
)
11+
from sysbrokers.IB.ib_contracts import ibContract
1212
from sysbrokers.IB.ib_connection import connectionIB
13+
from sysbrokers.IB.client.ib_client import ibClient
1314
from sysbrokers.broker_instrument_data import brokerFuturesInstrumentData
1415

15-
from syscore.constants import arg_not_supplied
16-
1716
from sysdata.data_blob import dataBlob
1817

1918
from syslogdiag.log_to_screen import logtoscreen
2019

2120

2221
class ibFuturesInstrumentData(brokerFuturesInstrumentData):
23-
"""
24-
Extends the baseData object to a data source that reads in and writes prices for specific futures contracts
25-
26-
This gets HISTORIC data from interactive brokers. It is blocking code
27-
In a live production system it is suitable for running on a daily basis to get end of day prices
28-
29-
"""
30-
3122
def __init__(
3223
self,
3324
ibconnection: connectionIB,
3425
data: dataBlob,
35-
log=logtoscreen("ibFuturesContractData"),
26+
log=logtoscreen("ibFuturesInstrumentData"),
3627
):
3728
super().__init__(log=log, data=data)
3829
self._ibconnection = ibconnection
3930

4031
def __repr__(self):
4132
return "IB Futures per contract data %s" % str(self.ibconnection)
4233

43-
@property
44-
def ibconnection(self) -> connectionIB:
45-
return self._ibconnection
46-
47-
def get_instrument_code_from_broker_code(
48-
self,
49-
ib_code: str,
50-
ib_multiplier: float = arg_not_supplied,
51-
ib_exchange: str = arg_not_supplied,
34+
def get_instrument_code_from_broker_contract_object(
35+
self, broker_contract_object: ibContract
5236
) -> str:
53-
config = self.ib_config
54-
broker_code = get_instrument_code_from_broker_code(
55-
config=config,
56-
ib_code=ib_code,
57-
log=self.log,
58-
ib_multiplier=ib_multiplier,
59-
ib_exchange=ib_exchange,
60-
)
6137

62-
return broker_code
38+
return self.ib_client.get_instrument_code_from_broker_contract_object(
39+
broker_contract_object
40+
)
6341

6442
def _get_instrument_data_without_checking(self, instrument_code: str):
6543
return self.get_futures_instrument_object_with_IB_data(instrument_code)
@@ -97,6 +75,20 @@ def ib_config(self) -> IBconfig:
9775

9876
return config
9977

78+
@property
79+
def ib_client(self) -> ibClient:
80+
client = getattr(self, "_ib_client", None)
81+
if client is None:
82+
client = self._ib_client = ibClient(
83+
ibconnection=self.ibconnection, log=self.log
84+
)
85+
86+
return client
87+
88+
@property
89+
def ibconnection(self) -> connectionIB:
90+
return self._ibconnection
91+
10092
def _get_and_set_ib_config_from_file(self) -> IBconfig:
10193

10294
config_data = read_ib_config_from_file(log=self.log)

sysbrokers/IB/ib_orders.py

+2-14
Original file line numberDiff line numberDiff line change
@@ -210,23 +210,11 @@ def _create_broker_control_order_object(
210210
"""
211211
try:
212212
try:
213-
## FIXME THIS IS HORRIFIC
214213
ib_contract = (
215214
trade_with_contract_from_ib.ibcontract_with_legs.ibcontract
216215
)
217-
ib_instrument_code = trade_with_contract_from_ib.ib_instrument_code
218-
219-
contract_details = self.ib_client.ib.reqContractDetails(ib_contract)
220-
221-
ib_exchange = contract_details[0].validExchanges
222-
ib_multiplier = contract_details[0].evMultiplier # is this right?
223-
224-
instrument_code = (
225-
self.futures_instrument_data.get_instrument_code_from_broker_code(
226-
ib_instrument_code,
227-
ib_exchange=ib_exchange,
228-
ib_multiplier=ib_multiplier,
229-
)
216+
instrument_code = self.futures_instrument_data.get_instrument_code_from_broker_contract_object(
217+
ib_contract
230218
)
231219
except:
232220
raise ibOrderCouldntCreateException()

0 commit comments

Comments
 (0)