1
- from datetime import time
2
- import pandas as pd
3
- from bar_features import state_to_bar
4
- from utils_filters import TickRule , MADFilter , JMAFilter
1
+ from bar_features import trades_to_bar
5
2
6
3
7
4
8
- class BarActor :
9
-
10
- def __init__ (self , thresh : dict ):
11
- self .state = reset_state (thresh )
12
- self .bars = []
13
-
14
- def update (self , tick : dict ):
15
- self .bars , self .state = update_bar_state (tick , self .state , self .bars , self .state ['thresh' ])
16
-
17
-
18
5
def reset_state (thresh : dict = {}) -> dict :
19
6
state = {}
20
7
state ['thresh' ] = thresh
@@ -37,24 +24,18 @@ def reset_state(thresh: dict={}) -> dict:
37
24
state ['stat' ]['dollar_imbalance' ] = 0
38
25
# copy of tick events
39
26
state ['trades' ] = {}
40
- state ['trades' ]['date_time ' ] = []
27
+ state ['trades' ]['nyc_time ' ] = []
41
28
state ['trades' ]['price' ] = []
42
29
state ['trades' ]['volume' ] = []
43
30
state ['trades' ]['side' ] = []
44
31
state ['trades' ]['jma' ] = []
45
32
# trigger status
46
- state ['trigger_yet?!' ] = 'waiting'
47
- return state
48
-
49
-
50
- def imbalance_net (state : dict ) -> dict :
51
- state ['stat' ]['tick_imbalance' ] += state ['trades' ]['side' ][- 1 ]
52
- state ['stat' ]['volume_imbalance' ] += (state ['trades' ]['side' ][- 1 ] * state ['trades' ]['volume' ][- 1 ])
53
- state ['stat' ]['dollar_imbalance' ] += (state ['trades' ]['side' ][- 1 ] * state ['trades' ]['volume' ][- 1 ] * state ['trades' ]['price' ][- 1 ])
33
+ state ['bar_trigger' ] = 'waiting'
54
34
return state
55
35
56
36
57
37
def imbalance_runs (state : dict ) -> dict :
38
+
58
39
if len (state ['trades' ]['side' ]) >= 2 :
59
40
if state ['trades' ]['side' ][- 1 ] == state ['trades' ]['side' ][- 2 ]:
60
41
state ['stat' ]['tick_run' ] += 1
@@ -64,7 +45,7 @@ def imbalance_runs(state: dict) -> dict:
64
45
state ['stat' ]['tick_run' ] = 0
65
46
state ['stat' ]['volume_run' ] = 0
66
47
state ['stat' ]['dollar_run' ] = 0
67
-
48
+
68
49
return state
69
50
70
51
@@ -91,45 +72,39 @@ def get_next_renko_thresh(renko_size: float, last_bar_return: float, reversal_mu
91
72
state ['thresh' ]['renko_bear' ] = - state ['thresh' ]['renko_size' ]
92
73
93
74
if state ['stat' ][state ['thresh' ]['renko_return' ]] >= state ['thresh' ]['renko_bull' ]:
94
- state ['trigger_yet?! ' ] = 'renko_up'
75
+ state ['bar_trigger ' ] = 'renko_up'
95
76
if state ['stat' ][state ['thresh' ]['renko_return' ]] < state ['thresh' ]['renko_bear' ]:
96
- state ['trigger_yet?! ' ] = 'renko_down'
77
+ state ['bar_trigger ' ] = 'renko_down'
97
78
98
79
if 'volume_imbalance' in state ['thresh' ] and abs (state ['stat' ]['volume_imbalance' ]) >= state ['thresh' ]['volume_imbalance' ]:
99
- state ['trigger_yet?! ' ] = 'volume_imbalance'
80
+ state ['bar_trigger ' ] = 'volume_imbalance'
100
81
101
82
if 'max_duration_td' in state ['thresh' ] and state ['stat' ]['duration_td' ] > state ['thresh' ]['max_duration_td' ]:
102
- state ['trigger_yet?! ' ] = 'duration'
83
+ state ['bar_trigger ' ] = 'duration'
103
84
104
85
# over-ride newbar trigger with 'minimum' thresholds
105
86
if 'min_duration_td' in state ['thresh' ] and state ['stat' ]['duration_td' ] < state ['thresh' ]['min_duration_td' ]:
106
- state ['trigger_yet?! ' ] = 'waiting'
87
+ state ['bar_trigger ' ] = 'waiting'
107
88
108
89
if 'min_tick_count' in state ['thresh' ] and state ['stat' ]['tick_count' ] < state ['thresh' ]['min_tick_count' ]:
109
- state ['trigger_yet?! ' ] = 'waiting'
90
+ state ['bar_trigger ' ] = 'waiting'
110
91
111
92
return state
112
93
113
94
114
- def update_bar_state (tick : dict , state : dict , bars : list , thresh : dict = {}) -> tuple :
115
-
116
- state ['trades' ]['date_time ' ].append (tick ['date_time ' ])
95
+ def update_bar_state (tick : dict , state : dict , bars : list = [] , thresh : dict = {}) -> tuple :
96
+ # append tick
97
+ state ['trades' ]['nyc_time ' ].append (tick ['nyc_time ' ])
117
98
state ['trades' ]['price' ].append (tick ['price' ])
118
- state ['trades' ]['jma' ].append (tick ['jma' ])
119
99
state ['trades' ]['volume' ].append (tick ['volume' ])
120
100
state ['trades' ]['side' ].append (tick ['side' ])
121
- # if len(state['trades']['price']) >= 2:
122
- # tick_side = tick_rule(
123
- # latest_price=state['trades']['price'][-1],
124
- # prev_price=state['trades']['price'][-2],
125
- # last_side=state['trades']['side'][-1],
126
- # )
127
- # else:
128
- # tick_side = 0
129
- # state['trades']['side'].append(tick_side)
130
- state = imbalance_net (state )
131
- # state = imbalance_runs(state)
132
- state ['stat' ]['duration_td' ] = state ['trades' ]['date_time' ][- 1 ] - state ['trades' ]['date_time' ][0 ]
101
+ state ['trades' ]['jma' ].append (tick ['jma' ])
102
+ # imbalances
103
+ state ['stat' ]['tick_imbalance' ] += state ['trades' ]['side' ][- 1 ]
104
+ state ['stat' ]['volume_imbalance' ] += (state ['trades' ]['side' ][- 1 ] * state ['trades' ]['volume' ][- 1 ])
105
+ state ['stat' ]['dollar_imbalance' ] += (state ['trades' ]['side' ][- 1 ] * state ['trades' ]['volume' ][- 1 ] * state ['trades' ]['price' ][- 1 ])
106
+ # other
107
+ state ['stat' ]['duration_td' ] = state ['trades' ]['nyc_time' ][- 1 ] - state ['trades' ]['nyc_time' ][0 ]
133
108
state ['stat' ]['tick_count' ] += 1
134
109
state ['stat' ]['volume' ] += tick ['volume' ]
135
110
state ['stat' ]['dollars' ] += tick ['price' ] * tick ['volume' ]
@@ -146,71 +121,24 @@ def update_bar_state(tick: dict, state: dict, bars: list, thresh: dict={}) -> tu
146
121
state ['stat' ]['jma_return' ] = tick ['jma' ] - state ['trades' ]['jma' ][0 ]
147
122
# check state tirggered sample threshold
148
123
state = check_bar_thresholds (state )
149
- if state ['trigger_yet?!' ] != 'waiting' :
150
- new_bar = state_to_bar (state )
124
+
125
+ if state ['bar_trigger' ] != 'waiting' :
126
+ # new_bar = state_to_bar(state)
127
+ new_bar = trades_to_bar (ticks = state ['trades' ])
151
128
bars .append (new_bar )
152
129
state = reset_state (thresh )
130
+ else :
131
+ new_bar = {'bar_trigger' : 'waiting' }
153
132
154
- return bars , state
155
-
133
+ return bars , state , new_bar
156
134
157
- def filter_tick (tick : dict , mad_filter : MADFilter , jma_filter : JMAFilter , tick_rule : TickRule ) -> dict :
158
135
159
- tick ['date_time' ] = tick ['sip_dt' ].tz_localize ('UTC' ).tz_convert ('America/New_York' )
160
-
161
- mad_filter .update (next_value = tick ['price' ]) # update mad filter
136
+ class BarSampler :
162
137
163
- irregular_conditions = [2 , 5 , 7 , 10 , 13 , 15 , 16 , 20 , 21 , 22 , 29 , 33 , 38 , 52 , 53 ]
164
-
165
- if tick ['volume' ] < 1 : # zero volume/size tick
166
- tick ['status' ] = 'zero_volume'
167
- elif pd .Series (tick ['conditions' ]).isin (irregular_conditions ).any (): # 'irrgular' tick condition
168
- tick ['status' ] = 'irregular_condition'
169
- elif abs (tick ['sip_dt' ] - tick ['exchange_dt' ]) > pd .to_timedelta (2 , unit = 'S' ): # remove large ts deltas
170
- tick ['status' ] = 'ts_delta'
171
- elif mad_filter .status != 'mad_clean' : # MAD filter outlier
172
- tick ['status' ] = 'mad_outlier'
173
- else : # 'clean' tick
174
- tick ['status' ] = 'clean'
175
- tick ['jma' ] = jma_filter .update (next_value = tick ['price' ]) # update jma filter
176
- tick ['side' ] = tick_rule .update (next_price = tick ['price' ]) # update tick rule
177
- if tick ['date_time' ].to_pydatetime ().time () < time (hour = 9 , minute = 30 ):
178
- tick ['status' ] = 'clean_pre_market'
179
- elif tick ['date_time' ].hour >= 16 :
180
- tick ['status' ] = 'clean_after_hours'
181
- else :
182
- tick ['status' ] = 'clean_open_market'
183
-
184
- # remove fields
185
- tick .pop ('sip_dt' , None )
186
- tick .pop ('exchange_dt' , None )
187
- tick .pop ('conditions' , None )
188
-
189
- return tick
190
-
138
+ def __init__ (self , thresh : dict ):
139
+ self .state = reset_state (thresh )
140
+ self .bars = []
191
141
192
- def build_bars (ticks_df : pd .DataFrame , thresh : dict ) -> tuple :
193
-
194
- mad_filter = MADFilter (thresh ['mad_value_winlen' ], thresh ['mad_deviation_winlen' ], thresh ['mad_k' ])
195
- jma_filter = JMAFilter (ticks_df ['price' ].values [0 ], thresh ['jma_winlen' ], thresh ['jma_power' ])
196
- tick_rule = TickRule ()
197
- bar_actor = BarActor (thresh )
198
- ticks = []
199
- for t in ticks_df .itertuples ():
200
- tick = {
201
- 'sip_dt' : t .sip_dt ,
202
- 'exchange_dt' : t .exchange_dt ,
203
- 'price' : t .price ,
204
- 'volume' : t .size ,
205
- 'conditions' : t .conditions ,
206
- 'status' : 'raw' ,
207
- }
208
- tick = filter_tick (tick , mad_filter , jma_filter , tick_rule )
209
-
210
- if tick ['status' ] == 'clean_open_market' :
211
- # if tick['status'].startswith('clean'):
212
- bar_actor .update (tick )
213
-
214
- ticks .append (tick )
215
-
216
- return bar_actor .bars , ticks
142
+ def update (self , tick : dict ):
143
+ self .bars , self .state , new_bar = update_bar_state (tick , self .state , self .bars , self .state ['thresh' ])
144
+ return new_bar
0 commit comments