[docs]@njitdefcorrect_local_timestamp(data:EVENT_ARRAY,base_latency:float)->EVENT_ARRAY:""" Adjusts the local timestamp `in place` if the feed latency is negative by offsetting it by the maximum negative latency value as follows: .. code-block:: feed_latency = local_timestamp - exch_timestamp adjusted_local_timestamp = local_timestamp + min(feed_latency, 0) + base_latency Args: data: Data to be corrected. base_latency: Due to discrepancies in system time between the exchange and the local machine, latency may be measured inaccurately, resulting in negative latency values. The conversion process automatically adjusts for positive latency but may still produce zero latency cases. By adding ``base_latency``, more realistic values can be obtained. Unit should be the same as the feed data's timestamp unit. Returns: Data with the corrected timestamps. """latency=sys.maxsizeforrow_numinrange(len(data)):exch_timestamp=data[row_num].exch_tslocal_timestamp=data[row_num].local_tslatency=min(latency,local_timestamp-exch_timestamp)iflatency<0:local_timestamp_offset=-latency+base_latencyprint('local_timestamp is ahead of exch_timestamp by',-latency)forrow_numinrange(len(data)):data[row_num].local_ts+=local_timestamp_offsetreturndata
[docs]@njitdefcorrect_event_order(data:EVENT_ARRAY,sorted_exch_index:NDArray,sorted_local_index:NDArray,)->EVENT_ARRAY:""" Corrects exchange timestamps that are reversed by splitting each row into separate events. These events are then ordered by both exchange and local timestamps through duplication. See the `data <https://hftbacktest.readthedocs.io/en/latest/data.html>`_ for details. Args: data: Data to be corrected. sorted_exch_index: Index of data sorted by exchange timestamp. sorted_local_index: Index of data sorted by local timestamp. Returns: Data with the corrected event order. """sorted_final=np.zeros(data.shape[0]*2,event_dtype)out_rn=0exch_rn=0local_rn=0whileTrue:sorted_exch=data[sorted_exch_index[exch_rn]]sorted_local=data[sorted_local_index[local_rn]]if(exch_rn<len(data)andlocal_rn<len(data)andsorted_exch.exch_ts==sorted_local.exch_tsandsorted_exch.local_ts==sorted_local.local_ts):assertsorted_exch.ev==sorted_local.evassert(sorted_exch.px==sorted_local.px)or(np.isnan(sorted_exch.px)andnp.isnan(sorted_local.px))assertsorted_exch.qty==sorted_local.qtysorted_final[out_rn]=sorted_exchsorted_final[out_rn].ev=sorted_final[out_rn].ev|EXCH_EVENT|LOCAL_EVENTout_rn+=1exch_rn+=1local_rn+=1elif((exch_rn<len(data)andlocal_rn<len(data)andsorted_exch.exch_ts==sorted_local.exch_tsandsorted_exch.local_ts<sorted_local.local_ts)or(exch_rn<len(data)andsorted_exch.exch_ts<sorted_local.exch_ts)):# exchangesorted_final[out_rn]=sorted_exchsorted_final[out_rn].ev=sorted_final[out_rn].ev|EXCH_EVENTout_rn+=1exch_rn+=1elif((exch_rn<len(data)andlocal_rn<len(data)andsorted_exch.exch_ts==sorted_local.exch_tsandsorted_exch.local_ts>sorted_local.local_ts)or(local_rn<len(data))):# localsorted_final[out_rn]=sorted_localsorted_final[out_rn].ev=sorted_final[out_rn].ev|LOCAL_EVENTout_rn+=1local_rn+=1elifexch_rn<len(data):# exchangesorted_final[out_rn]=sorted_exchsorted_final[out_rn].ev=sorted_final[out_rn].ev|EXCH_EVENTout_rn+=1exch_rn+=1else:assertexch_rn==len(data)assertlocal_rn==len(data)breakreturnsorted_final[:out_rn]
[docs]defvalidate_event_order(data:EVENT_ARRAY)->None:""" Validates that the order of events is correct. If the data contains an incorrect event order, a :class:`ValueError` will be raised. Args: data: Data to validate. """exch_ev=data['ev']&EXCH_EVENT==EXCH_EVENTlocal_ev=data['ev']&LOCAL_EVENT==LOCAL_EVENTifnp.sum(np.diff(data['exch_ts'][exch_ev])<0)>0:raiseValueError('exchange events are out of order.')ifnp.sum(np.diff(data['local_ts'][local_ev])<0)>0:raiseValueError('local events are out of order.')