@@ -34,6 +34,8 @@ class Range(Strategy):
34
34
used to size the orders per grid level.
35
35
"""
36
36
37
+ MAX_ORDERS = 16
38
+
37
39
def __init__ (
38
40
self ,
39
41
parameters : dict ,
@@ -159,7 +161,6 @@ def check_orders(self, new_orders: list[Order]):
159
161
else :
160
162
# This order is in the target - mark as existing
161
163
# by removing from missing_orders dict
162
- # TODO - check size?
163
164
grid_no = target_prices .index (Decimal (str (price ))) + 1
164
165
missing_orders [direction ].pop (grid_no )
165
166
@@ -169,8 +170,41 @@ def check_orders(self, new_orders: list[Order]):
169
170
sell_levels_filled = - min (0 , np .ceil (net_position / self .order_size ))
170
171
grid_levels_filled = {1 : buy_levels_filled , - 1 : sell_levels_filled }
171
172
172
- # Create orders for missing levels
173
+ # Set limits on orders to be placed - only place up to MAX_ORDERS orders at a time.
174
+ # This means if more than MAX_ORDERS levels are specified for the grid, only the
175
+ # closest MAX_ORDERS should be placed.
173
176
mid_price = Decimal (str (self .exchange .get_orderbook (self .instrument ).midprice ))
177
+
178
+ # Calculate distance of midprice from each level of buy and sell prices
179
+ distances = {
180
+ d : {l : abs (mid_price - p ) for l , p in ps .items ()}
181
+ for d , ps in self .target_order_prices .items ()
182
+ }
183
+ min_d = {d : {min (v , key = v .get ): min (v .values ())} for d , v in distances .items ()}
184
+ dir_mins = {d : min (v .values ()) for d , v in min_d .items ()}
185
+
186
+ # Determine order direction mid price is closest too
187
+ direction = min (dir_mins , key = dir_mins .get )
188
+
189
+ # Determine nearest level matching the direction
190
+ nearest_level = min_d [direction ].popitem ()[0 ]
191
+
192
+ # Calculate allowable grid ranges for each direction
193
+ levels_per_side = int (np .ceil (self .MAX_ORDERS / 2 ))
194
+ allowed_levels = {
195
+ direction : [
196
+ i
197
+ for i in range (
198
+ nearest_level - levels_per_side , nearest_level + levels_per_side
199
+ )
200
+ if i > 0
201
+ ]
202
+ }
203
+ allowed_levels [- direction ] = [
204
+ i for i in range (1 , self .MAX_ORDERS - len (allowed_levels [direction ]) + 1 )
205
+ ]
206
+
207
+ # Create orders for missing levels
174
208
for direction , orders in missing_orders .items ():
175
209
for grid_no , order_price in orders .items ():
176
210
# Check order price against current mid price
@@ -179,8 +213,11 @@ def check_orders(self, new_orders: list[Order]):
179
213
# Check current position to prevent replacing an order already filled
180
214
level_not_filled = grid_no > grid_levels_filled [direction ]
181
215
216
+ # Check grid_no is in the allowed levels
217
+ place_level = grid_no in allowed_levels [direction ]
218
+
182
219
# Check both conditions
183
- if price_valid and level_not_filled :
220
+ if price_valid and level_not_filled and place_level :
184
221
# Proceed with order
185
222
o = Order (
186
223
instrument = self .instrument ,
0 commit comments