Пример #1
0
    def check(self, messages: [ReconMessage], *args, **kwargs) -> Event:
        logger.info(
            f"RULE '{self.get_name()}': CHECK: input_messages: {messages}")

        ignore_fields = [
            'CheckSum', 'BodyLength', 'SendingTime', 'TargetCompID', 'PartyID',
            'OrderID', 'CumQty', 'OrderQty', 'ExecID', 'LeavesQty',
            'MsgSeqNum', 'Price', 'TimeInForce', 'Side', 'Text', 'OrdStatus',
            'ClOrdID'
        ]
        verification_component = self.message_comparator.compare_messages(
            messages, ignore_fields)

        info_for_name = dict()
        for message in messages:
            info_for_name.update(message.hash_info)

        body = EventUtils.create_event_body(verification_component)
        attach_ids = [msg.proto_message.metadata.id for msg in messages]

        return EventUtils.create_event(
            name=f"Match by '{ReconMessage.get_info(info_for_name)}'",
            status=verification_component.status,
            attached_message_ids=attach_ids,
            body=body)
Пример #2
0
    def store_no_match_within_timeout(self, rule_event_id: EventID, recon_message: ReconMessage,
                                      actual_timestamp: int, timeout: int):
        name = f'{recon_message.all_info}'

        units = ['sec', 'ms', 'mcs', 'ns']
        factor_units = [1_000_000_000, 1_000_000, 1_000, 1]
        for unit, factor_unit in zip(units, factor_units):
            if not any((actual_timestamp % factor_unit, recon_message.timestamp % factor_unit, timeout % factor_unit)):
                break

        actual_timestamp = int(actual_timestamp / factor_unit)
        message_timestamp = int(recon_message.timestamp / factor_unit)
        timeout = int(timeout / factor_unit)

        event_message = f"Timestamp of the last received message: '{actual_timestamp:,}' {unit}\n" \
                        f"Timestamp this message: '{message_timestamp:,}' {unit}\n" \
                        f"Timeout: '{timeout:,}' {unit}"
        body = EventUtils.create_event_body(MessageComponent(event_message))
        attached_message_ids = self._get_attached_message_ids(recon_message)
        event = EventUtils.create_event(name=name,
                                        body=body,
                                        attached_message_ids=attached_message_ids,
                                        type=EventUtils.EventType.EVENT)
        logger.debug("Create '%s' Event for rule Event '%s'", self.NO_MATCH_WITHIN_TIMEOUT, rule_event_id)
        self.send_event(event, rule_event_id, self.NO_MATCH_WITHIN_TIMEOUT)
Пример #3
0
    def __init__(self, recon: Recon, cache_size: int, match_timeout: int,
                 autoremove_timeout: Optional[int], configuration) -> None:
        self.recon = recon
        self.configure(configuration)
        self.name = self.get_name()
        logger.info("Rule '%s' initializing...", self.name)

        self.event_store = recon.event_store
        self.message_comparator: Optional[
            MessageComparator] = recon.message_comparator
        self.match_timeout = match_timeout
        self.autoremove_timeout = autoremove_timeout

        self.reprocess_queue = list()

        self.rule_event: Event = \
            EventUtils.create_event(name=self.name,
                                    parent_id=recon.event_store.root_event.id,
                                    body=EventUtils.create_event_body(MessageComponent(message=self.get_description())),
                                    type=EventUtils.EventType.RULE)
        logger.debug(
            "Created report Event for Rule '%s': %s", self.name,
            text_format.MessageToString(self.rule_event, as_one_line=True))
        self.event_store.send_parent_event(self.rule_event)

        self.__cache = Cache(self, cache_size)

        self.RULE_PROCESSING_TIME = Histogram(
            f"th2_recon_{re.sub('[^a-zA-Z0-9_: ]', '', self.name).lower().replace(' ', '_')}_rule_processing_time",
            'Time of the message processing with a rule',
            buckets=common_metrics.DEFAULT_BUCKETS)

        logger.info("Rule '%s' initialized", self.name)
Пример #4
0
    def check(self, messages: [ReconMessage], *args, **kwargs) -> Event:
        logger.info(f"RULE '{self.get_name()}': CHECK: ")

        table_component = TableComponent([
            'Session alias', 'MessageType', 'ExecType', 'ClOrdID', 'Group ID'
        ])
        for msg in messages:
            msg_type = msg.proto_message.metadata.message_type
            exec_type = msg.proto_message.fields['ExecType'].simple_value
            cl_ord_id = msg.proto_message.fields['ClOrdID'].simple_value
            session_alias = msg.proto_message.metadata.id.connection_id.session_alias
            table_component.add_row(session_alias, msg_type, exec_type,
                                    cl_ord_id, msg.group_id)

        info_for_name = dict()
        for message in messages:
            info_for_name.update(message.hash_info)

        body = EventUtils.create_event_body(table_component)
        attach_ids = [msg.proto_message.metadata.id for msg in messages]
        return EventUtils.create_event(
            name=
            f"Match by '{ReconMessage.get_info(info_for_name)}' from 3 group",
            attached_message_ids=attach_ids,
            body=body)
Пример #5
0
    def store_no_match_within_timeout(self, rule_event_id: EventID,
                                      recon_message: ReconMessage,
                                      actual_timestamp: int, timeout: int):
        name = f'{recon_message.get_all_info()}'
        message_timestamp = MessageUtils.get_timestamp_ns(
            recon_message.proto_message)

        units = ['sec', 'ms', 'mcs', 'ns']
        factor_units = [1_000_000_000, 1_000_000, 1_000, 1]
        units_idx = 0
        while actual_timestamp % factor_units[units_idx] != 0 \
                or message_timestamp % factor_units[units_idx] != 0 \
                or timeout % factor_units[units_idx] != 0:
            units_idx += 1

        unit = units[units_idx]
        actual_timestamp = int(actual_timestamp / factor_units[units_idx])
        message_timestamp = int(message_timestamp / factor_units[units_idx])
        timeout = int(timeout / factor_units[units_idx])

        event_message = f"Timestamp of the last received message: '{actual_timestamp:,}' {unit}\n" \
                        f"Timestamp this message: '{message_timestamp:,}' {unit}\n" \
                        f"Timeout: '{timeout:,}' {unit}"
        body = EventUtils.create_event_body(MessageComponent(event_message))
        attached_message_ids = [recon_message.proto_message.metadata.id]
        event = EventUtils.create_event(
            name=name, body=body, attached_message_ids=attached_message_ids)
        logger.info(
            f"Create '{self.NO_MATCH_WITHIN_TIMEOUT}' Event for rule Event '{rule_event_id}'"
        )
        self.send_event(event, rule_event_id, self.NO_MATCH_WITHIN_TIMEOUT)
Пример #6
0
 def store_error(self, rule_event_id: EventID, event_name: str, error_message: str,
                 messages: List[ReconMessage] = None):
     body = EventUtils.create_event_body(MessageComponent(error_message))
     attached_message_ids = self._get_attached_message_ids(*messages)
     event = EventUtils.create_event(name=event_name,
                                     status=EventStatus.FAILED,
                                     attached_message_ids=attached_message_ids,
                                     body=body,
                                     type=EventUtils.EventType.EVENT)
     logger.debug("Create '%s' Event for rule Event '%s'", self.ERRORS, rule_event_id)
     self.send_event(event, rule_event_id, self.ERRORS)
Пример #7
0
 def store_message_removed(self, rule_event_id: EventID, message: ReconMessage, event_message: str):
     name = f"Remove {message.all_info}"
     event_message += f"\n Message {'not' if not message.is_matched else ''} matched"
     body = EventUtils.create_event_body(MessageComponent(event_message))
     attached_message_ids = self._get_attached_message_ids(message)
     event = EventUtils.create_event(name=name,
                                     body=body,
                                     status=EventStatus.SUCCESS if message.is_matched else EventStatus.FAILED,
                                     attached_message_ids=attached_message_ids,
                                     type=EventUtils.EventType.EVENT)
     logger.debug("Create '%s' Event for rule Event '%s'", self.NO_MATCH, rule_event_id)
     self.send_event(event, rule_event_id, self.NO_MATCH)
Пример #8
0
 def store_no_match(self, rule_event_id: EventID, message: ReconMessage,
                    event_message: str):
     name = f"Remove '{message.proto_message.metadata.message_type}' {message.get_all_info()}"
     event_message += f"\n Message {'not' if not message.is_matched else ''} matched"
     body = EventUtils.create_event_body(MessageComponent(event_message))
     attached_message_ids = [message.proto_message.metadata.id]
     event = EventUtils.create_event(
         name=name,
         body=body,
         status=EventStatus.SUCCESS
         if message.is_matched else EventStatus.FAILED,
         attached_message_ids=attached_message_ids)
     logger.info(
         f"Create '{self.NO_MATCH}' Event for rule Event '{rule_event_id}'")
     self.send_event(event, rule_event_id, self.NO_MATCH)
Пример #9
0
    def check(self, messages: [ReconMessage]) -> Event:
        logger.info(f"RULE '{self.get_name()}': CHECK: input_messages: {messages}")

        ignore_fields = ['CheckSum', 'BodyLength', 'SendingTime', 'TransactTime', 'MsgSeqNum', 'ClOrdID']
        verification_component = self.message_comparator.compare_messages(messages, ignore_fields)

        info_for_name = dict()
        for message in messages:
            info_for_name.update(message.hash_info)

        body = EventUtils.create_event_body(verification_component)
        attach_ids = [msg.proto_message.metadata.id for msg in messages]
        return EventUtils.create_event(name=f"Match by '{ReconMessage.get_info(info_for_name)}'",
                                       status=verification_component.status,
                                       attached_message_ids=attach_ids,
                                       body=body)
Пример #10
0
 def store_error(self,
                 rule_event_id: EventID,
                 event_name: str,
                 error_message: str,
                 messages: [ReconMessage] = None):
     body = EventUtils.create_event_body(MessageComponent(error_message))
     attached_message_ids = [
         message.proto_message.metadata.id for message in messages
     ]
     event = EventUtils.create_event(
         name=event_name,
         status=EventStatus.FAILED,
         attached_message_ids=attached_message_ids,
         body=body)
     logger.info(
         f"Create '{self.ERRORS}' Event for rule Event '{rule_event_id}'")
     self.send_event(event, rule_event_id, self.ERRORS)
Пример #11
0
    def send_event(self, event: Event, rule_event_id: EventID, group_event_name: str):
        try:
            if rule_event_id.id not in self.__group_event_by_rule_id:
                self.__group_event_by_rule_id[rule_event_id.id] = dict()
            if group_event_name not in self.__group_event_by_rule_id[rule_event_id.id]:
                group_event = EventUtils.create_event(parent_id=rule_event_id,
                                                      name=group_event_name,
                                                      type=EventUtils.EventType.STATUS)
                logger.debug(f"Create group Event '%s' for rule Event '%s'", group_event_name, rule_event_id)
                self.__group_event_by_rule_id[rule_event_id.id][group_event_name] = group_event
                self.send_parent_event(group_event)

            group_event = self.__group_event_by_rule_id[rule_event_id.id][group_event_name]
            event.id.CopyFrom(EventUtils.new_event_id())
            event.parent_id.CopyFrom(group_event.id)
            self.__events_batch_collector.put_event(event)
        except Exception:
            logger.exception(f'Error while sending event')
Пример #12
0
    def __init__(self, event_router: EventBatchRouter, report_name: str, event_batch_max_size: int,
                 event_batch_send_interval: int) -> None:
        self.event_router = event_router
        self.__events_batch_collector = EventsBatchCollector(event_router, event_batch_max_size,
                                                             event_batch_send_interval)
        self.__group_event_by_rule_id = dict()

        self.root_event: Event = EventUtils.create_event(name='Recon: ' + report_name, type=EventUtils.EventType.ROOT)
        logger.debug('Created root report Event for Recon: %s',
                     text_format.MessageToString(self.root_event, as_one_line=True))
        self.send_parent_event(self.root_event)
Пример #13
0
    def __init__(self, event_router: EventBatchRouter, report_name: str,
                 event_batch_max_size: int,
                 event_batch_send_interval: int) -> None:
        self.event_router = event_router
        self.__events_batch_collector = EventsBatchCollector(
            event_router, event_batch_max_size, event_batch_send_interval)
        self.__group_event_by_rule_id = dict()

        self.root_event: Event = EventUtils.create_event(name='Recon: ' +
                                                         report_name)
        logger.info(f'Created root report Event for Recon: {self.root_event}')
        self.send_parent_event(self.root_event)
Пример #14
0
    def send_event(self, event: Event, rule_event_id: EventID,
                   group_event_name: str):
        try:
            if not self.__group_event_by_rule_id.__contains__(
                    rule_event_id.id):
                self.__group_event_by_rule_id[rule_event_id.id] = dict()
            if not self.__group_event_by_rule_id[
                    rule_event_id.id].__contains__(group_event_name):
                group_event = EventUtils.create_event(parent_id=rule_event_id,
                                                      name=group_event_name)
                logger.info(
                    f"Create group Event '{group_event_name}' for rule Event '{rule_event_id}'"
                )
                self.__group_event_by_rule_id[
                    rule_event_id.id][group_event_name] = group_event
                self.send_parent_event(group_event)

            group_event = self.__group_event_by_rule_id[
                rule_event_id.id][group_event_name]
            event.id.CopyFrom(EventUtils.new_event_id())
            event.parent_id.CopyFrom(group_event.id)
            self.__events_batch_collector.put_event(event)
        except Exception:
            logger.exception(f'Error while sending event')
Пример #15
0
    def check(self, messages: [ReconMessage], *args, **kwargs) -> Event:
        message_types = []
        cl_order_id = messages[0].proto_message.fields['ClOrdID'].simple_value
        latency_type = 'Unknown'
        recv_msg: Message = None
        send_msg: Message = None
        recv_msg_type: str = ''
        send_msg_type: str = ''
        explanation = None

        msg: ReconMessage
        for msg in messages:
            message = msg.proto_message
            message_type = message.metadata.message_type
            message_types.append(message_type)
            if msg.group_id == Group.RESPONSE:
                recv_msg = msg.proto_message
                recv_msg_type = message_type
            else:
                send_msg = msg.proto_message
                send_msg_type = message_type

        if recv_msg_type == 'ExecutionReport':
            exec_type = recv_msg.fields['ExecType'].simple_value
            ord_status = recv_msg.fields['OrdStatus'].simple_value

            logger.info(f"RULE '{self.get_name()}': "
                        f"CHECK: messageER: [ClOrdID:{cl_order_id}, "
                        f"ExecType: {exec_type}, "
                        f"OrdStatus: {ord_status}]")

            if send_msg_type == 'NewOrderSingle':
                if exec_type == 'A' and ord_status == 'A':
                    latency_type = 'PendingNew'
                elif exec_type == '0' and ord_status == '0':
                    latency_type = 'New'
                elif exec_type == 'F' and ord_status in ['1', '2'] and \
                        recv_msg.fields['LastLiquidityInd'].simple_value == '2':
                    latency_type = 'Trade'
                elif exec_type == '8' and ord_status == '8':
                    latency_type = 'NewReject'

            elif send_msg_type == 'OrderCancelRequest':
                if exec_type == '6' and ord_status == '6':
                    latency_type = 'PendingCancel'
                elif (exec_type == '4' and ord_status == '4') or (exec_type == 'C' and ord_status == 'C'):
                    latency_type = 'Cancel'
                
            elif send_msg_type == 'OrderCancelReplaceRequest':
                if exec_type == 'E' and ord_status == 'E':
                    latency_type = 'PendingReplace'
                elif exec_type == '5' and ord_status in ['0', '1']:
                    latency_type = 'Replace'

            # Should be always in the end.
            if latency_type == 'Unknown':
                explanation = MessageComponent(f"Attention! Unknown messages combination. \n"
                                               f"ER[ExecType]: {exec_type}, ER[OrdStatus]: {ord_status}\n\n"
                                               f" --------------- Recv msg --------------- \n {recv_msg}\n"
                                               f" --------------- Send msg --------------- \n {send_msg}")

        elif recv_msg_type == 'OrderCancelReject':
            if send_msg_type == 'OrderCancelReplaceRequest':
                latency_type = 'ReplaceReject'

            elif send_msg_type == 'OrderCancelRequest':
                latency_type = 'CancelReject'

        else:
            logger.error(f"RULE '{self.get_name()}': "
                        f"CHECK: Unknown message received. "
                        f"Msg types: {message_types}\n"
                        f"Recv msg: {recv_msg}\n"
                        f"Send msg: {send_msg}")

        type1, type2, latency = latency_check(recv_msg, send_msg)

        table = TableComponent(['Name', 'Value'])
        table.add_row('ClOrdId', cl_order_id)
        table.add_row('Message Response', type1)
        table.add_row('Message Request', type2)
        table.add_row('Latency type', latency_type)
        table.add_row('Latency', latency)
        event_message = f'{type1} and {type2} ' \
                        f'Latency_type: {latency_type} ' \
                        f'Latency = {latency}'
        logger.info(
            f"RULE '{self.get_name()}': Thread: {threading.current_thread().name}: "
            f"EventMessage={event_message}. Latency was calculated for {cl_order_id} between {message_types[0]} "
            f"and {message_types[1]}")

        if explanation is None:
            body = EventUtils.create_event_body(table)
        else:
            body = EventUtils.create_event_body([table, explanation])
        attach_ids = [msg.proto_message.metadata.id for msg in messages]
        status = EventStatus.SUCCESS if latency < self.LATENCY_LIMIT else EventStatus.FAILED
        return EventUtils.create_event(name=f"Match by ClOrdID: '{cl_order_id}'",
                                       status=status,
                                       attached_message_ids=attach_ids,
                                       body=body)