Skip to content

Commit

Permalink
feat(Strategy): range bot can optionally have origin order
Browse files Browse the repository at this point in the history
  • Loading branch information
kieran-mackle committed Mar 25, 2024
1 parent 01074f9 commit e7cb515
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 10 deletions.
11 changes: 6 additions & 5 deletions src/cryptobots/config/range.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ MODULE: 'range'
CLASS: 'Range'
INTERVAL: '10s'
PARAMETERS:
lower_price: 50
upper_price: 60
no_levels: 40
max_position: 20
WATCHLIST: ['AVAX/USDT:USDT']
lower_price: 3150
upper_price: 3500
no_levels: 20
max_position: 0.1
origin_direction: 1
WATCHLIST: ['ETH/USDT:USDT']
INCLUDE: ["INTERVAL"] # used when displaying params in CLI, exclude others
BACKTEST_READY: False
28 changes: 23 additions & 5 deletions src/cryptobots/strategies/range.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,28 +66,37 @@ def __init__(
self.upper_price = Decimal(str(parameters["upper_price"]))
self.no_levels = int(2 * np.ceil(float(parameters["no_levels"]) / 2))
self.max_position = Decimal(str(parameters["max_position"]))
self.origin_direction = np.sign(int(parameters["origin_direction"]))

# Initialise state
self.ref_price = (self.upper_price + self.lower_price) / 2
self.origin_price = ((self.upper_price + self.lower_price) / 2).quantize(
self.price_precision
)
self.order_size = (2 * self.max_position / self.no_levels).quantize(
self.size_precision
)
self.grid_space = (
(self.upper_price - self.lower_price) / self.no_levels
).quantize(self.price_precision)
buy_prices = {
i: self.ref_price - i * self.grid_space
i: self.origin_price - i * self.grid_space
for i in range(1, int(self.no_levels / 2) + 1)
}
sell_prices = {
i: self.ref_price + i * self.grid_space
i: self.origin_price + i * self.grid_space
for i in range(1, int(self.no_levels / 2) + 1)
}
self.target_order_prices = {1: buy_prices, -1: sell_prices}

# Check for origin order
if self.origin_direction != 0:
# Add origin price to target prices
self.target_order_prices[self.origin_direction][0] = self.origin_price

self.logger.info(f"Order size per level: {self.order_size} units.")
self.logger.info(
f"Estimated profit per level: ${self.grid_space*self.order_size:,} "
+ f"(~{100*self.grid_space/self.ref_price:.2f}%)."
+ f"(~{100*self.grid_space/self.origin_price:.2f}%)."
)

def generate_signal(self, dt: datetime) -> Order | List[Order] | None:
Expand Down Expand Up @@ -181,6 +190,12 @@ def check_orders(self, new_orders: list[Order]):
for d, lp in self.target_order_prices.items()
}

# Check for origin order
if self.origin_direction != 0:
# Add origin order to allowable levels
allowed_levels[self.origin_direction].append(0)
target_order_prices[self.origin_direction][0] = self.origin_price

# Keep track of target orders which exist
missing_orders = deepcopy(target_order_prices)

Expand Down Expand Up @@ -217,7 +232,10 @@ def check_orders(self, new_orders: list[Order]):
price_valid = direction * (mid_price - order_price) > 0

# Check current position to prevent replacing an order already filled
level_not_filled = grid_no > grid_levels_filled[direction]
level_not_filled = (
grid_levels_filled[direction] == 0
or grid_no > grid_levels_filled[direction]
)

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

0 comments on commit e7cb515

Please sign in to comment.