def connect(self, config_server_addr, verbose=True): """Talk to the config server and get addresses for all available order engines and market data feeds, return an order manager which is connected to all order sockets """ config_socket = self.config_socket print 'Requesting configuation from', config_server_addr config_socket.connect(config_server_addr) config_socket.send('C') response = poll_single_socket(config_socket) if response is None: raise RuntimeError('Config server is down') [tag, msg] = response assert tag == 'CONFIG' config = venue_configuration_pb2.configuration() config.ParseFromString(msg) for venue_config in config.configs: venue_id = int(venue_config.venue_id) mic_name = str(venue_config.mic_name) print print 'Reading config for mic = %s, venue_id = %s' \ % (mic_name, venue_id) ping_addr = str(venue_config.order_ping_addr) order_addr = str(venue_config.order_interface_addr) md_addr = str(venue_config.market_data_broadcast_addr) log_addr = str(venue_config.logging_broadcast_addr) vc = venue_capabilities(venue_id) venue_attrs.venue_specifics[venue_id] = vc if venue_config.use_synthetic_cancel_replace is True: print 'Setting synthetic_cancel_replace for: %d' % venue_id venue_attrs.venue_specifics[venue_id].use_synthetic_cancel_replace = True problem_with_addr = False for addr in [ping_addr, order_addr, md_addr]: if not address_ok(addr): print 'Malformed address', addr problem_with_addr = True if problem_with_addr: print 'Skipping', mic_name continue order_control_socket = \ connect_to_order_engine_controller(ping_addr) if order_control_socket: print 'Ping succeeded, adding sockets...' (order_socket, venue_id2) = \ connect_to_order_engine(order_addr, self.strategy_id_bytes, mic_name) assert venue_id == venue_id2 self.order_sockets[venue_id] = order_socket self.mic_names[venue_id] = mic_name self.order_control_sockets[venue_id] = \ order_control_socket self.md_socket.connect(md_addr) if self.symbols is None: self.md_socket.setsockopt(zmq.SUBSCRIBE, '') else: for s in self.symbols: self.md_socket.setsockopt(zmq.SUBSCRIBE, s) names = self.mic_names.values() if len(names) > 0: print print '----------------------------' print 'Succeeded in connecting to: ', ', '.join(names) print '----------------------------' print else: raise RuntimeError("Couldn't find any active venues") # return the set of valid venue_ids self.order_manager = OrderManager(self.strategy_id_bytes, self.order_sockets) return self.order_manager
class Strategy: def __init__(self, strategy_id, symbols=None): self.strategy_id = uuid.UUID(strategy_id) self.strategy_id_bytes = self.strategy_id.bytes # market data socket self.md_socket = context.socket(zmq.SUB) # map from venue_id to order socket self.order_sockets = {} # map from venue_id to order ping/control socket self.order_control_sockets = {} # map from venue_id to MIC name of venue self.mic_names = {} # which symbols should MD sockets listen for? self.symbols = None self.config_socket = context.socket(zmq.REQ) self.order_manager = None def connect(self, config_server_addr, verbose=True): """Talk to the config server and get addresses for all available order engines and market data feeds, return an order manager which is connected to all order sockets """ config_socket = self.config_socket print 'Requesting configuation from', config_server_addr config_socket.connect(config_server_addr) config_socket.send('C') response = poll_single_socket(config_socket) if response is None: raise RuntimeError('Config server is down') [tag, msg] = response assert tag == 'CONFIG' config = venue_configuration_pb2.configuration() config.ParseFromString(msg) for venue_config in config.configs: venue_id = int(venue_config.venue_id) mic_name = str(venue_config.mic_name) print print 'Reading config for mic = %s, venue_id = %s' \ % (mic_name, venue_id) ping_addr = str(venue_config.order_ping_addr) order_addr = str(venue_config.order_interface_addr) md_addr = str(venue_config.market_data_broadcast_addr) log_addr = str(venue_config.logging_broadcast_addr) vc = venue_capabilities(venue_id) venue_attrs.venue_specifics[venue_id] = vc if venue_config.use_synthetic_cancel_replace is True: print 'Setting synthetic_cancel_replace for: %d' % venue_id venue_attrs.venue_specifics[venue_id].use_synthetic_cancel_replace = True problem_with_addr = False for addr in [ping_addr, order_addr, md_addr]: if not address_ok(addr): print 'Malformed address', addr problem_with_addr = True if problem_with_addr: print 'Skipping', mic_name continue order_control_socket = \ connect_to_order_engine_controller(ping_addr) if order_control_socket: print 'Ping succeeded, adding sockets...' (order_socket, venue_id2) = \ connect_to_order_engine(order_addr, self.strategy_id_bytes, mic_name) assert venue_id == venue_id2 self.order_sockets[venue_id] = order_socket self.mic_names[venue_id] = mic_name self.order_control_sockets[venue_id] = \ order_control_socket self.md_socket.connect(md_addr) if self.symbols is None: self.md_socket.setsockopt(zmq.SUBSCRIBE, '') else: for s in self.symbols: self.md_socket.setsockopt(zmq.SUBSCRIBE, s) names = self.mic_names.values() if len(names) > 0: print print '----------------------------' print 'Succeeded in connecting to: ', ', '.join(names) print '----------------------------' print else: raise RuntimeError("Couldn't find any active venues") # return the set of valid venue_ids self.order_manager = OrderManager(self.strategy_id_bytes, self.order_sockets) return self.order_manager def close_all(self): print 'Running cleanup code' sockets = [self.md_socket] + self.order_sockets.values() \ + self.order_control_sockets.values() for socket in sockets: socket.setsockopt(zmq.LINGER, 0) socket.close() def _synchronize_market_data(self, md_update, wait_time=0.5): """For a short period only receive market data without taking any actions. Every time a new piece of market data arrives, parse it and call 'md_update' with the parsed struct """ logging.debug('Synchronizing market data') poller = zmq.Poller() poller.register(self.md_socket, zmq.POLLIN) start_time = time.time() while time.time() < start_time + wait_time: ready_sockets = dict(poller.poll(1000)) if ready_sockets.get(self.md_socket) == zmq.POLLIN: bbo = spot_fx_md_1_pb2.instrument_bbo() msg = self.md_socket.recv() bbo.ParseFromString(msg) md_update(bbo) print 'Waited', wait_time, 'seconds, entering main loop' def run(self, md_update, place_orders, order_first=False): self._synchronize_market_data(md_update) poller = zmq.Poller() md_socket = self.md_socket poller.register(md_socket, zmq.POLLIN) print 'ORDER SOCKETS:', self.order_sockets print 'ORDER SOCKET VALUES: ', self.order_sockets.values() for order_socket in self.order_sockets.values(): poller.register(order_socket, zmq.POLLIN) while True: if order_first == True: place_orders() ready_sockets = poller.poll() for (socket, state) in ready_sockets: # ignore errors for now if state == zmq.POLLERR: print 'POLLERR on socket', socket, 'md socket = ', \ self.md_socket, 'order sockets = ', \ self.order_sockets elif state == zmq.POLLIN: if socket == md_socket: msg = md_socket.recv() bbo = spot_fx_md_1_pb2.instrument_bbo() msg = md_socket.recv() bbo.ParseFromString(msg) md_update(bbo) else: [tag, msg] = socket.recv_multipart() tag = int_from_bytes(tag) self.order_manager.received_message_from_order_engine(tag, msg) place_orders()