def run(self, hub, message): connection = Connection(self.url, self.session) connection.start() # get hub hub = connection.hub(hub) hub.server.invoke('send_message', message) connection.close()
def request_order_book(self): try: with Session() as session: connection = Connection(self.url, session) self.hub = connection.register_hub(self.hub_name) connection.received += self.on_receive connection.start() while self.order_book_is_received is not True: self.hub.server.invoke( BittrexParameters.QUERY_EXCHANGE_STATE, self.pair_name) connection.wait( 5 ) # otherwise it shoot thousands of query and we will be banned :( connection.close() msg = "Got orderbook for Bittrex!" log_to_file(msg, SOCKET_ERRORS_LOG_FILE_NAME) print(msg) return STATUS.SUCCESS except Exception as e: # log_error_on_receive_from_socket("Bittrex", e) msg = "Error during order book retrieval for Bittrex {}".format( str(e)) log_to_file(msg, SOCKET_ERRORS_LOG_FILE_NAME) print(msg) return STATUS.FAILURE
def get_value(self, hub, method): self.res = {} with Session() as session: #create a connection connection = Connection(self.url, session) chat = connection.register_hub(hub) chat.client.on(method, self.update_res) connection.start() connection.wait(3) connection.close() return self.res
class SignalRHubSensor(Sensor): def __init__(self, sensor_service, config=None): super(SignalRHubSensor, self).__init__(sensor_service=sensor_service, config=config) self._logger = self._sensor_service.get_logger(__name__) self.url = config['hub_url'] self.hub_name = config['hub_name'] self._trigger_ref = 'signalr.message_received' self._hub = None self.connection = None self.session = None def setup(self): self.connection = Connection(self.url, self.session) # start a connection self.connection.start() # add a handler to process notifications to the connection self.connection.handlers += \ lambda data: self._logger.debug( 'Connection: new notification - %s' % data) # get hub self._hub = self.connection.hub(self.hub_name) def message_received(self, message): self._logger.debug('Connection: new notification.' % message) self._sensor_service.dispatch(trigger=self._trigger_ref, payload={message: message}) def run(self): self._hub.client.on('message_received', SignalRHubSensor.message_received) def cleanup(self): # do not receive new messages self._hub.client.off('message_received', self.message_received) self.connection.close()
class OnlineSignalR(OnlineCore): __worker_thread = None __worker_thread_event = None __personal_portfolio_queue_lock = Lock() __personal_portfolio_queue = [] __securities_options_repos_queue_lock = Lock() __securities_options_repos_queue = [] __order_book_queue_lock = Lock() __order_book_queue = [] def __init__(self, auth, on_open=None, on_personal_portfolio=None, on_securities=None, on_options=None, on_repos=None, on_order_book=None, on_error=None, on_close=None, proxy_url=None): """ Class constructor. Parameters ---------- auth : home_broker_session An object with the authentication information. on_open : function(), optional Callable object which is called at opening the signalR connection. This function has no argument. on_personal_portfolio : function(quotes), optional Callable object which is called when personal portfolio data is received. This function has 1 argument. The argument is the dataframe with the quotes. on_securities : function(quotes), optional Callable object which is called when security data is received. This function has 1 argument. The argument is the dataframe with the quotes. on_options : function(quotes), optional Callable object which is called when options data is received. This function has 1 argument. The argument is the dataframe with the quotes. on_repos : function(quotes), optional Callable object which is called when repo data is received. This function has 1 argument. The argument is the dataframe with the quotes. on_order_book : function(quotes), optional Callable object which is called when the order book data (level 2) is received. This function has 1 argument. The argument is the dataframe with the quotes. on_error : function(exception, connection_lost), optional Callable object which is called when we get error. This function has 2 arguments. The 1st argument is the exception object. The 2nd argument is if the connection was lost due to the error. on_close : function(), optional Callable object which is called when closed the connection. This function has no argument. proxy_url : str, optional The proxy URL with one of the following formats: - scheme://user:pass@hostname:port - scheme://user:pass@ip:port - scheme://hostname:port - scheme://ip:port Ex. https://john:[email protected]:3128 """ self._proxies = { 'http': proxy_url, 'https': proxy_url } if proxy_url else None self._auth = auth self._on_open = on_open self._on_personal_portfolio = on_personal_portfolio self._on_securities = on_securities self._on_options = on_options self._on_repos = on_repos self._on_order_book = on_order_book self._on_error = on_error self._on_close = on_close self._connection = None self._hub = None self.is_connected = False ######################## #### PUBLIC METHODS #### ######################## def connect(self): """ Connects to the signalR server. Raises ------ pyhomebroker.exceptions.SessionException If the user is not logged in. """ if not self._auth.is_user_logged_in: raise SessionException('User is not logged in') url = '{}/signalr/hubs'.format(self._auth.broker['page']) with rq.Session() as session: rq.utils.add_dict_to_cookiejar(session.cookies, self._auth.cookies) if self._proxies: session.proxies.update(self._proxies) session.headers = {'User-Agent': user_agent} self._connection = Connection(url, session) self._hub = self._connection.register_hub('stockpriceshub') self._hub.client.on('broadcast', self.__internal_securities_options_repos) self._hub.client.on('sendStartStockFavoritos', self.__internal_personal_portfolio) self._hub.client.on('sendStockFavoritos', self.__internal_personal_portfolio) self._hub.client.on('sendStartStockPuntas', self.__internal_order_book) self._hub.client.on('sendStockPuntas', self.__internal_order_book) if self._on_error: self._connection.error += self._on_error self._connection.exception += self.__on_internal_exception self._connection.start() self.is_connected = self._connection.is_open if self.is_connected and self._on_open: self._on_open() self.__worker_thread_event = Event() self.__worker_thread = Thread(target=self.__worker_thread_run) self.__worker_thread.start() def disconnect(self): """ Disconnects from the signalR server. Raises ------ pyhomebroker.exceptions.SessionException If the user is not logged in. If the connection or hub is not assigned. """ if not self._auth.is_user_logged_in: raise SessionException('User is not logged in') if not self._connection or not self._hub: raise SessionException('Connection or hub is not assigned') if self._connection.is_open: self._connection.close() self._connection = None self._hub = None self.is_connected = False if self._on_close: self._on_close() self.__worker_thread_stop() def join_group(self, group_name): """ Subscribe to a group to start receiving event notifications. Raises ------ pyhomebroker.exceptions.SessionException If the user is not logged in. If the connection or hub is not assigned. If the connection is not open. """ if not self._auth.is_user_logged_in: raise SessionException('User is not logged in') if not self._connection or not self._hub: raise SessionException('Connection or hub is not assigned') if not self._connection.is_open: raise SessionException('Connection is not open') self._hub.server.invoke('JoinGroup', group_name) def quit_group(self, group_name): """ Unsubscribe from a group to stop receiving event notifications. Raises ------ pyhomebroker.exceptions.SessionException If the user is not logged in. If the connection or hub is not assigned. If the connection is not open. """ if not self._auth.is_user_logged_in: raise SessionException('User is not logged in') if not self._connection or not self._hub: raise SessionException('Connection or hub is not assigned') if not self._connection.is_open: raise SessionException('Connection is not open') self._hub.server.invoke('QuitGroup', group_name) ######################### #### PRIVATE METHODS #### ######################### def __worker_thread_run(self): while not self.__worker_thread_event.wait(0.1): with self.__personal_portfolio_queue_lock: data = self.__personal_portfolio_queue self.__personal_portfolio_queue = [] self.__process_personal_portfolio(data) with self.__securities_options_repos_queue_lock: data = self.__securities_options_repos_queue self.__securities_options_repos_queue = [] self.__process_securities_options_repos(data) with self.__order_book_queue_lock: data = self.__order_book_queue self.__order_book_queue = [] self.__process_order_books(data) def __worker_thread_stop(self): if self.__worker_thread_event and not self.__worker_thread_event.is_set( ): self.__worker_thread_event.set() self.__worker_thread.join() self.__worker_thread_event = None self.__worker_thread = None def __process_personal_portfolio(self, data): try: # Handle any exception processing the information or triggered by the user code if not self._on_personal_portfolio or len(data) == 0: return ts = time.time() # Remove duplicates from Json Document data_filter = {} for item in data: data_filter[item['Symbol'] + '-' + item['Term']] = item data = list(data_filter.values()) df_portfolio = self.process_personal_portfolio(data) ts_pp_process = time.time() df_order_book = self.process_order_books(data) ts_ob_process = time.time() self._on_personal_portfolio(df_portfolio, df_order_book) ts_event = time.time() logging.debug( "[HOMEBROKER: SIGNALR] Performance [__process_personal_portfolio (P: {} - OB: {})]: (PP Proc: {:.3f}s - OB Proc: {:.3f}s - Notif: {:.3f}s)" .format(len(df_portfolio.index), len(df_order_book.index), ts_pp_process - ts, ts_ob_process - ts_pp_process, ts_event - ts_ob_process)) except Exception as ex: if self._on_error: try: # Catch user exceptions inside the except block (Inception Mode Activated :D) self._on_error(ex, False) except: pass def __process_securities_options_repos(self, data): try: # Handle any exception processing the information or triggered by the user code if len(data) == 0: return # Remove duplicates from Json Document data_filter = {} for item in data: data_filter[item['Symbol'] + '-' + item['Term']] = item data = list(data_filter.values()) df = pd.DataFrame(data) if data else pd.DataFrame() df_repo = df[df.Group == 'cauciones-'].copy() df_options = df[df.Group == 'opciones-'].copy() df_securities = df[(df.Group != 'cauciones-') & (df.Group != 'opciones-')].copy() if len(df_repo) and self._on_repos: ts = time.time() repos = self.process_repos(df_repo) ts_process = time.time() self._on_repos(repos) ts_event = time.time() logging.debug( "[HOMEBROKER: SIGNALR] Performance [__process_securities_options_repos (R: {})]: (Proc: {:.3f}s - Notif: {:.3f}s)" .format(len(repos.index), ts_process - ts, ts_event - ts_process)) if len(df_options) and self._on_options: ts = time.time() options = self.process_options(df_options) ts_process = time.time() self._on_options(options) ts_event = time.time() logging.debug( "[HOMEBROKER: SIGNALR] Performance [__process_securities_options_repos (O: {})]: (Proc: {:.3f}s - Notif: {:.3f}s)" .format(len(options.index), ts_process - ts, ts_event - ts_process)) if len(df_securities) and self._on_securities: ts = time.time() securities = self.process_securities(df_securities) ts_process = time.time() self._on_securities(securities) ts_event = time.time() logging.debug( "[HOMEBROKER: SIGNALR] Performance [__process_securities_options_repos (S: {})]: (Proc: {:.3f}s - Notif: {:.3f}s)" .format(len(securities.index), ts_process - ts, ts_event - ts_process)) except Exception as ex: if self._on_error: try: # Catch user exceptions inside the except block (Inception Mode Activated :D) self._on_error(ex, False) except: pass def __process_order_books(self, data): try: # Handle any exception processing the information or triggered by the user code if not self._on_order_book or len(data) == 0: return ts = time.time() # Remove duplicates from Json Document data_filter = {} for item in data: data_filter[item['Symbol'] + '-' + item['Term']] = item data = list(data_filter.values()) order_books = self.process_order_books(data) ts_process = time.time() self._on_order_book(order_books) ts_event = time.time() logging.debug( "[HOMEBROKER: SIGNALR] Performance [__process_order_books ({})]: (Proc: {:.3f}s - Notif: {:.3f}s)" .format(len(data), ts_process - ts, ts_event - ts_process)) except Exception as ex: if self._on_error: try: # Catch user exceptions inside the except block (Inception Mode Activated :D) self._on_error(ex, False) except: pass ############################################# #### PRIVATE METHODS - SIGNALR CALLBACKS #### ############################################# def __internal_personal_portfolio(self, data): if not data: return if not isinstance(data, list): data = [data] with self.__personal_portfolio_queue_lock: self.__personal_portfolio_queue.extend(data) def __internal_securities_options_repos(self, data): if not data: return if not isinstance(data, list): data = [data] with self.__securities_options_repos_queue_lock: self.__securities_options_repos_queue.extend(data) def __internal_order_book(self, data): if not data: return if not isinstance(data, list): data = [data] with self.__order_book_queue_lock: self.__order_book_queue.extend(data) def __on_internal_exception(self, exception_type, value, traceback): self.__worker_thread_stop() if self._on_error: try: # Catch user exceptions inside the except block (Inception Mode Activated :D) self._on_error(exception_type(value), True) except: pass
centralview.client.on('toggleServiceInfo',centralview_toggleServiceInfo) centralview.client.on('setVersion', centralview_setVersion) connection.error += loading_error #start a connection connection.start() time.sleep(10) while not connection.started: print("connecting...") print(connection.id) connectionId = connection.id #create a connection raw_html = simple_get(session,build_url("/Home/SaveConnectionId",{"lang":"Pl","connectionId":connectionId,"mac":mac,"id":id,"password":password})) print(raw_html) if raw_html is None: #if connectionSaved: connection.close() connectionStopped = True # simple_get(build_url("/Home/GetUsername",{"userId":connectionId})) while not connectionStopped: time.sleep(1)
class OnlineSignalR: def __init__(self, auth, on_open=None, on_personal_portfolio=None, on_securities=None, on_options=None, on_repos=None, on_order_book=None, on_error=None, on_close=None, proxy_url=None): """ Class constructor. Parameters ---------- auth : home_broker_session An object with the authentication information. on_open : function(), optional Callable object which is called at opening the signalR connection. This function has no argument. on_personal_portfolio : function(quotes), optional Callable object which is called when personal portfolio data is received. This function has 1 argument. The argument is the dataframe with the quotes. on_securities : function(quotes), optional Callable object which is called when security data is received. This function has 1 argument. The argument is the dataframe with the quotes. on_options : function(quotes), optional Callable object which is called when options data is received. This function has 1 argument. The argument is the dataframe with the quotes. on_repos : function(quotes), optional Callable object which is called when repo data is received. This function has 1 argument. The argument is the dataframe with the quotes. on_order_book : function(quotes), optional Callable object which is called when the order book data (level 2) is received. This function has 1 argument. The argument is the dataframe with the quotes. on_error : function(error), optional Callable object which is called when we get error. This function has 1 arguments. The argument is the exception object. on_close : function(), optional Callable object which is called when closed the connection. This function has no argument. proxy_url : str, optional The proxy URL with one of the following formats: - scheme://user:pass@hostname:port - scheme://user:pass@ip:port - scheme://hostname:port - scheme://ip:port Ex. https://john:[email protected]:3128 """ self._proxies = {'http': proxy_url, 'https': proxy_url} if proxy_url else None self._auth = auth self._on_open = on_open self._on_personal_portfolio = on_personal_portfolio self._on_securities = on_securities self._on_options = on_options self._on_repos = on_repos self._on_order_book = on_order_book self._on_error = on_error self._on_close = on_close self._connection = None self._hub = None self.is_connected = False ######################## #### PUBLIC METHODS #### ######################## def connect(self): """ Connects to the signalR server. Raises ------ pyhomebroker.exceptions.SessionException If the user is not logged in. """ if not self._auth.is_user_logged_in: raise SessionException('User is not logged in') url = '{}/signalr/hubs'.format(self._auth.broker['page']) with rq.Session() as session: rq.utils.add_dict_to_cookiejar(session.cookies, self._auth.cookies) if self._proxies: session.proxies.update(self._proxies) self._connection = Connection(url, session) self._hub = self._connection.register_hub('stockpriceshub') self._hub.client.on('broadcast', self.__internal_securities_options_repos) self._hub.client.on('sendStartStockFavoritos', self.__internal_personal_portfolio) self._hub.client.on('sendStockFavoritos', self.__internal_personal_portfolio) self._hub.client.on('sendStartStockPuntas', self.__internal_order_book) self._hub.client.on('sendStockPuntas', self.__internal_order_book) if self._on_error: self._connection.error += self._on_error self._connection.exception += self.__on_internal_exception self._connection.start() self.is_connected = self._connection.is_open if self.is_connected and self._on_open: self._on_open() def disconnect(self): """ Disconnects from the signalR server. Raises ------ pyhomebroker.exceptions.SessionException If the user is not logged in. If the connection or hub is not assigned. """ if not self._auth.is_user_logged_in: raise SessionException('User is not logged in') if not self._connection or not self._hub: raise SessionException('Connection or hub is not assigned') if self._connection.is_open: self._connection.close() self._connection = None self._hub = None self.is_connected = False if self._on_close: self._on_close() def join_group(self, group_name): """ Subscribe to a group to start receiving event notifications. Raises ------ pyhomebroker.exceptions.SessionException If the user is not logged in. If the connection or hub is not assigned. If the connection is not open. """ if not self._auth.is_user_logged_in: raise SessionException('User is not logged in') if not self._connection or not self._hub: raise SessionException('Connection or hub is not assigned') if not self._connection.is_open: raise SessionException('Connection is not open') self._hub.server.invoke('JoinGroup', group_name) def quit_group(self, group_name): """ Unsubscribe from a group to stop receiving event notifications. Raises ------ pyhomebroker.exceptions.SessionException If the user is not logged in. If the connection or hub is not assigned. If the connection is not open. """ if not self._auth.is_user_logged_in: raise SessionException('User is not logged in') if not self._connection or not self._hub: raise SessionException('Connection or hub is not assigned') if not self._connection.is_open: raise SessionException('Connection is not open') self._hub.server.invoke('QuitGroup', group_name) ######################### #### PRIVATE METHODS #### ######################### def __internal_personal_portfolio(self, data): try: # Handle any exception processing the information or triggered by the user code if self._on_personal_portfolio: if data and not isinstance(data, list): data = [data] df = pd.DataFrame(data if data else pd.DataFrame()) self._on_personal_portfolio(helper.process_personal_portfolio(df)) except Exception as ex: if self._on_error: try: # Catch user exceptions inside the except block (Inception Mode Activated :D) self._on_error(ex) except: pass def __internal_securities_options_repos(self, data): try: # Handle any exception processing the information or triggered by the user code df = pd.DataFrame(data) if data else pd.DataFrame() df_repo = df[df.Group == 'cauciones-'] df_options = df[df.Group == 'opciones-'] df_securities = df[(df.Group != 'cauciones-') & (df.Group != 'opciones-')] if len(df_repo) and self._on_repos: self._on_repos(helper.process_repos(df_repo)) if len(df_options) and self._on_options: self._on_options(helper.process_options(df_options)) if len(df_securities) and self._on_securities: self._on_securities(helper.process_securities(df_securities)) except Exception as ex: if self._on_error: try: # Catch user exceptions inside the except block (Inception Mode Activated :D) self._on_error(ex) except: pass def __internal_order_book(self, data): try: # Handle any exception processing the information or triggered by the user code if self._on_order_book and data: symbol = data['Symbol'] settlement = data['Term'] if data['StockDepthBox'] and data['StockDepthBox']['PriceDepthBox']: df_buy = pd.DataFrame(data['StockDepthBox']['PriceDepthBox']['BuySide']) df_sell = pd.DataFrame(data['StockDepthBox']['PriceDepthBox']['SellSide']) else: df_buy = pd.DataFrame() df_sell = pd.DataFrame() self._on_order_book(helper.process_order_book(symbol, settlement, df_buy, df_sell)) except Exception as ex: if self._on_error: try: # Catch user exceptions inside the except block (Inception Mode Activated :D) self._on_error(ex) except: pass def __on_internal_exception(self, exception_type, value, traceback): if self._on_error: self._on_error(exception_type(value))
class SubscriptionBittrex: def __init__(self, pair_id, on_update=default_on_public, base_url=BittrexParameters.URL, hub_name=BittrexParameters.HUB): """ :param pair_id: - currency pair to be used for trading :param base_url: - web-socket subscription end points :param hub_name: - Bittrex-specific url for market update :param on_update: - idea is the following: we pass reference to method WITH initialized order book for that pair_id whenever we receive update we update order book and trigger checks for arbitrage """ self.url = base_url self.hub_name = hub_name self.pair_id = pair_id self.pair_name = get_currency_pair_to_bittrex(self.pair_id) self.on_update = on_update self.hub = None self.order_book_is_received = False self.initial_order_book = None self.should_run = False def on_public(self, args): msg = process_message(args) log_to_file(msg, "bittrex.log") order_book_delta = parse_socket_update_bittrex(msg) if order_book_delta is None: err_msg = "Bittrex - cant parse update from message: {msg}".format( msg=msg) log_to_file(err_msg, SOCKET_ERRORS_LOG_FILE_NAME) else: self.on_update(EXCHANGE.BITTREX, order_book_delta) def on_receive(self, **kwargs): """ heart beat and other stuff :param kwargs: :return: """ if 'R' in kwargs and type(kwargs['R']) is not bool: msg = process_message(kwargs['R']) log_to_file(msg, "bittrex.log") if msg is not None: self.order_book_is_received = True self.initial_order_book = parse_socket_order_book_bittrex( msg, self.pair_id) else: try: msg = process_message(str(kwargs)) except: msg = kwargs log_to_file(msg, "bittrex.log") def request_order_book(self): try: with Session() as session: connection = Connection(self.url, session) self.hub = connection.register_hub(self.hub_name) connection.received += self.on_receive connection.start() while self.order_book_is_received is not True: self.hub.server.invoke( BittrexParameters.QUERY_EXCHANGE_STATE, self.pair_name) connection.wait( 5 ) # otherwise it shoot thousands of query and we will be banned :( connection.close() msg = "Got orderbook for Bittrex!" log_to_file(msg, SOCKET_ERRORS_LOG_FILE_NAME) print(msg) return STATUS.SUCCESS except Exception as e: # log_error_on_receive_from_socket("Bittrex", e) msg = "Error during order book retrieval for Bittrex {}".format( str(e)) log_to_file(msg, SOCKET_ERRORS_LOG_FILE_NAME) print(msg) return STATUS.FAILURE def subscribe(self): # # FIXME DBG PART - REMOVE AFTER TESTS # if self.should_run: die_hard("Bittrex another running?") msg = "Bittrex - call subscribe!" log_to_file(msg, SOCKET_ERRORS_LOG_FILE_NAME) print msg self.should_run = True try: with Session() as session: self.connection = Connection(self.url, session) self.hub = self.connection.register_hub(self.hub_name) self.hub.client.on(BittrexParameters.MARKET_DELTA, self.on_public) self.connection.start() log_conect_to_websocket("Bittrex") while self.connection.started and self.should_run: try: self.hub.server.invoke( BittrexParameters.SUBSCRIBE_EXCHANGE_DELTA, self.pair_name) except Exception as e: log_send_heart_beat_failed("Bittrex", e) # FIXME NOTE - still not sure - connection.wait(1) self.should_run = False break sleep_for(1) except Exception as e: log_error_on_receive_from_socket("Bittrex", e) log_subscription_cancelled("Bittrex") self.disconnect() def disconnect(self): self.should_run = False # FIXME NOTE: due to implementation of bittrex order book retrieval # dedicated method that create and destroy new instance of bittrex subscription # we are not really relying on this flag anywhere # self.order_book_is_received = False try: self.connection.close() except Exception as e: log_websocket_disconnect("Bittrex", e) def is_running(self): return self.should_run