class OCGateway(object): def __init__(self, oc_ip='10.10.1.53', oc_port='9031', user='******', password='******', version='v3.2', api_port='6001', publish_port='6002'): self._oc_ip = oc_ip self._oc_port = oc_port self._user = user self._password = password self._version = version self._api_port = api_port self._publish_port = publish_port self._supported_instruments_list = [] self._expiry_set = set() self._parent_symbol_set = set() self._month_id_to_parent_symbol_dict = {} self._oc_inst_id_to_internal_asset_id_dict = {} self._oc_month_id_to_oc_class_id_dict = {} self._internal_asset_id_to_oc_inst_id_dict = {} self._internal_asset_id_to_oc_class_id_dict = {} self._oc_inst_id_to_OCInst_dict = {} self._internal_asset_id_to_OCInst_dict = {} self._month_id_to_expiry_dict = {} self._month_id_to_instruments_list_dict = defaultdict(list) self._parent_symbol_to_instruments_list_dict = defaultdict(list) self._lookup_dicts_initialized = Event() self._oc_position_manager = OCPositionManager(self) self._oc_curve_manager = OCCurveManager(self) self._greenlets = [] def start(self): self._start_oc_bridge(self._oc_ip, self._oc_port, self._user, self._password, self._version) # wait to start api server until initial data download complete self._lookup_dicts_initialized.wait() self._start_zerorpc_api(self._api_port) log.info("startup complete") gevent.joinall(self._greenlets) def _start_oc_bridge(self, oc_ip, oc_port, user, password, version): self._oc_bridge = OCBridge(self, oc_ip, oc_port, user, password, version) self._greenlets.append(gevent.spawn(self._oc_bridge.start)) log.info("OCBridge initialized") def _start_zerorpc_api(self, api_port): self._api_server = zerorpc.Server(PublicAPI(self)) self._api_server.bind("tcp://*:{}".format(api_port)) self._api_server.bind("inproc://*:{}".format(api_port)) self._greenlets.append(gevent.spawn(self._api_server.run)) log.info("public api started") def shutdown(self): self._oc_bridge.shutdown() ####################### # message forwarding def send_message(self, message): self._oc_bridge.send_message(message) def async_request(self, async_req_message): return self._oc_bridge.async_request(async_req_message) ####################### # public table lookups def get_oc_class_id_from_internal_asset_id(self, asset_id): return self._internal_asset_id_to_oc_class_id_dict[asset_id] def get_oc_inst_id_from_internal_asset_d(self, asset_id): return self._internal_asset_id_to_oc_inst_id_dict[asset_id] def get_internal_asset_id_from_oc_inst_id(self, instrument_id): return self._oc_inst_id_to_internal_asset_id_dict.get(instrument_id, None) def get_oc_class_id_from_oc_month_id(self, month_id): return self._oc_month_id_to_oc_class_id_dict[month_id] def get_parent_symbol_from_month_id(self, month_id): return self._month_id_to_parent_symbol_dict[month_id] def get_instruments_by_month_id(self, month_id): return self._month_id_to_instruments_list_dict[month_id] def get_instruments_by_parent_symbol(self, parent_symbol): return self._parent_symbol_to_instruments_list_dict[parent_symbol] def get_expiry_from_month_id(self, month_id): return self._month_id_to_expiry_dict[month_id] def add_supported_instruments(self, new_instruments): self._supported_instruments_list.extend(new_instruments) self._save_supported_instruments(new_instruments) self._update_lookup_dicts(new_instruments) # initialize position manager for parent_symbol in self._parent_symbol_set: log.info("initializing position: {}".format(parent_symbol)) self.get_position_by_product(parent_symbol) ####################### # initialization methods def _update_lookup_dicts(self, new_instruments): self._log_parent_symbols(new_instruments) self._build_internal_ids_to_oc_ids_dicts() self._update_derivative_lookup_dicts(new_instruments) self._build_OCInst_lookup_dicts(new_instruments) self._build_parent_symbol_to_instruments_list_dict(new_instruments) self._lookup_dicts_initialized.set() def _build_OCInst_lookup_dicts(self, new_instruments): for inst in new_instruments: asset_id = self.get_internal_asset_id_from_oc_inst_id(inst.instrument_id) if asset_id is not None: self._internal_asset_id_to_OCInst_dict[asset_id] = inst self._oc_inst_id_to_OCInst_dict[inst.instrument_id] = inst def _log_parent_symbols(self, new_instruments): for inst in new_instruments: parent_symbol = inst.parent_symbol if parent_symbol not in self._parent_symbol_set: self._parent_symbol_set.add(parent_symbol) self.get_position_by_product(parent_symbol) def _build_parent_symbol_to_instruments_list_dict(self, new_instruments): for inst in new_instruments: self._parent_symbol_to_instruments_list_dict[inst.parent_symbol].append(inst) def _update_derivative_lookup_dicts(self, new_instruments): new_derivatives = [instrument for instrument in new_instruments if isinstance(instrument, OCDerivative)] for new_derivative in new_derivatives: expiry = new_derivative.get_expiry() self._expiry_set.add(expiry) self._month_id_to_expiry_dict[expiry.month_id] = expiry self._oc_month_id_to_oc_class_id_dict[expiry.month_id] = expiry.class_id self._month_id_to_parent_symbol_dict[expiry.month_id] = expiry.parent_symbol self._month_id_to_instruments_list_dict[expiry.month_id].append(new_derivative) ####################### # persistence handlers def _save_supported_instruments(self, new_instruments): # save all supported instruments to file save_instruments_to_file(self._supported_instruments_list) # convert new OCInstruments to internal Assets and save new Assets in database save_assets_to_db(new_instruments) def _build_internal_ids_to_oc_ids_dicts(self): assetid_classid_instid_tuples = get_assetid_occlassid_ocid_tuples() asset_ids = [acit[0] for acit in assetid_classid_instid_tuples] oc_class_ids = (acit[1] for acit in assetid_classid_instid_tuples) oc_inst_ids = [acit[2] for acit in assetid_classid_instid_tuples] self._internal_asset_id_to_oc_class_id_dict = dict(izip(asset_ids, oc_class_ids)) self._internal_asset_id_to_oc_inst_id_dict = dict(izip(asset_ids, oc_inst_ids)) self._oc_inst_id_to_internal_asset_id_dict = dict(izip(oc_inst_ids, asset_ids)) self._lookup_dicts_initialized.set() ####################### # market data request handlers # TODO: refactor into market data handler object def get_parent_symbols(self): return list(self._parent_symbol_set) def get_expiries(self, parent_symbol=None): if parent_symbol: expiries = [exp for exp in self._expiry_set if exp.parent_symbol == parent_symbol] else: expiries = list(self._expiry_set) return expiries def get_instruments(self): return self._supported_instruments_list def get_market_snapshot(self, asset_id): class_id = self.get_oc_class_id_from_internal_asset_id(asset_id) instrument_id = self.get_oc_inst_id_from_internal_asset_d(asset_id) market_data = self._get_market_snapshot(class_id, instrument_id) return market_data def _get_market_snapshot(self, class_id, instrument_id): snapshot_message = MarketSnapshotReqMessage(class_id, instrument_id) market_data = snapshot_message.get_result(self._oc_bridge) return market_data def get_theo_values(self, asset_id, underlying_price=None): instrument_id = self.get_oc_inst_id_from_internal_asset_d(asset_id) result = self._get_theo_values(instrument_id, underlying_price) return result def _get_theo_values(self, instrument_id, underlying_price=None): tvr_message = TheoValuesReqMessage(instrument_id, underlying_price) result = tvr_message.get_result(self._oc_bridge) return result def get_theo_values_bulk(self, month_id, underlying_price=None): if underlying_price is None: underlying_price = self.get_underlying_price_for_month(month_id) instrument_list = self._month_id_to_instruments_list_dict[month_id] greenlets = [gevent.spawn(self._get_theo_values, instrument.instrument_id, underlying_price) for instrument in instrument_list] gevent.joinall(greenlets) results = {greenlet.value['instrument_id']: greenlet.value for greenlet in greenlets} return results def get_underlying_price_for_month(self, month_id): instrument_list = self._month_id_to_instruments_list_dict[month_id] theo_value_result = self._get_theo_values(instrument_list[0].instrument_id) underlying_price = theo_value_result["underlying_price"] return underlying_price def get_theo_values_with_risk(self, asset_id, underlying_price=None): inst_id = self.get_oc_inst_id_from_internal_asset_d(asset_id) tvwrr_message = TheoValuesReqWithRiskMessage(inst_id, underlying_price) result = tvwrr_message.get_result(self._oc_bridge) return result def on_market_data_update(self, asset_id, market_data): pass def get_underlying_price_for_instrument(self, instrument_id): return self._get_theo_values(instrument_id)["underlying_price"] ####################### # model settings update implementations def on_model_update_notification(self): self._oc_curve_manager.on_model_update_notification() def get_model_settings(self, month_id): model_settings = self._oc_curve_manager.get_model_settings(month_id) return model_settings def get_model_settings_bulk(self, parent_symbol): # request expiry settings for individual expiries matching parent symbol expiries = self.get_expiries(parent_symbol) greenlets = [gevent.spawn(self._oc_curve_manager.get_model_settings, expiry.month_id) for expiry in expiries] gevent.joinall(greenlets) model_settings_list = [greenlet.value for greenlet in greenlets] return model_settings_list def set_model_settings(self, **kwargs): new_settings = self._oc_curve_manager.set_model_settings(**kwargs) return new_settings def move_model_inputs_by_price(self, **kwargs): new_settings = self._oc_curve_manager.move_model_inputs_by_price(**kwargs) return new_settings ####################### # position reporting functionality def get_position_by_product(self, parent_symbol): instruments = self._parent_symbol_to_instruments_list_dict[parent_symbol] greenlets = [gevent.spawn(self._oc_position_manager.get_position_by_instrument_id, inst.instrument_id) for inst in instruments] gevent.joinall(greenlets) positions = [greenlet.value for greenlet in greenlets] return positions def log_trade(self, trade_message): self._oc_position_manager.log_trade(trade_message)