Skip to content

Commit

Permalink
fix(Strategy): range bot has maximum orders to place at one time
Browse files Browse the repository at this point in the history
only the nearest MAX_ORDERS number of orders will be placed, to comply with exchange limits
  • Loading branch information
kieran-mackle committed Mar 23, 2024
1 parent 2cb4394 commit 5e19ad7
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 8 deletions.
10 changes: 5 additions & 5 deletions src/cryptobots/config/range.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ MODULE: 'range'
CLASS: 'Range'
INTERVAL: '10s'
PARAMETERS:
lower_price: 0.34
upper_price: 0.4
no_levels: 20
max_position: 50
WATCHLIST: ['POLYX/USDT:USDT']
lower_price: 50
upper_price: 60
no_levels: 40
max_position: 20
WATCHLIST: ['AVAX/USDT:USDT']
INCLUDE: ["INTERVAL"] # used when displaying params in CLI, exclude others
BACKTEST_READY: False
43 changes: 40 additions & 3 deletions src/cryptobots/strategies/range.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class Range(Strategy):
used to size the orders per grid level.
"""

MAX_ORDERS = 16

def __init__(
self,
parameters: dict,
Expand Down Expand Up @@ -159,7 +161,6 @@ def check_orders(self, new_orders: list[Order]):
else:
# This order is in the target - mark as existing
# by removing from missing_orders dict
# TODO - check size?
grid_no = target_prices.index(Decimal(str(price))) + 1
missing_orders[direction].pop(grid_no)

Expand All @@ -169,8 +170,41 @@ def check_orders(self, new_orders: list[Order]):
sell_levels_filled = -min(0, np.ceil(net_position / self.order_size))
grid_levels_filled = {1: buy_levels_filled, -1: sell_levels_filled}

# Create orders for missing levels
# Set limits on orders to be placed - only place up to MAX_ORDERS orders at a time.
# This means if more than MAX_ORDERS levels are specified for the grid, only the
# closest MAX_ORDERS should be placed.
mid_price = Decimal(str(self.exchange.get_orderbook(self.instrument).midprice))

# Calculate distance of midprice from each level of buy and sell prices
distances = {
d: {l: abs(mid_price - p) for l, p in ps.items()}
for d, ps in self.target_order_prices.items()
}
min_d = {d: {min(v, key=v.get): min(v.values())} for d, v in distances.items()}
dir_mins = {d: min(v.values()) for d, v in min_d.items()}

# Determine order direction mid price is closest too
direction = min(dir_mins, key=dir_mins.get)

# Determine nearest level matching the direction
nearest_level = min_d[direction].popitem()[0]

# Calculate allowable grid ranges for each direction
levels_per_side = int(np.ceil(self.MAX_ORDERS / 2))
allowed_levels = {
direction: [
i
for i in range(
nearest_level - levels_per_side, nearest_level + levels_per_side
)
if i > 0
]
}
allowed_levels[-direction] = [
i for i in range(1, self.MAX_ORDERS - len(allowed_levels[direction]) + 1)
]

# Create orders for missing levels
for direction, orders in missing_orders.items():
for grid_no, order_price in orders.items():
# Check order price against current mid price
Expand All @@ -179,8 +213,11 @@ def check_orders(self, new_orders: list[Order]):
# Check current position to prevent replacing an order already filled
level_not_filled = grid_no > grid_levels_filled[direction]

# Check grid_no is in the allowed levels
place_level = grid_no in allowed_levels[direction]

# Check both conditions
if price_valid and level_not_filled:
if price_valid and level_not_filled and place_level:
# Proceed with order
o = Order(
instrument=self.instrument,
Expand Down

0 comments on commit 5e19ad7

Please sign in to comment.