Skip to content

Commit

Permalink
[GridTrading] add test and log
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeDSM committed Jan 26, 2025
1 parent a9ea307 commit e37bf67
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 2 deletions.
13 changes: 11 additions & 2 deletions Trading/Mode/grid_trading_mode/grid_trading.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ async def _generate_staggered_orders(self, current_price, ignore_available_funds
highest_buy = current_price
lowest_sell = current_price
origin_created_buy_orders_count, origin_created_sell_orders_count = self._get_origin_orders_count(
sorted_orders, recently_closed_trades
recently_closed_trades, sorted_orders
)

min_max_total_order_price_delta = (
Expand Down Expand Up @@ -485,6 +485,12 @@ async def _generate_staggered_orders(self, current_price, ignore_available_funds
self.logger.info(
f"{len(missing_orders)} missing {self.symbol} orders on {self.exchange_name}: {missing_orders}"
)
else:
self.logger.info(
f"All {len(sorted_orders)} out of {self.buy_orders_count + self.sell_orders_count} {self.symbol} "
f"target orders are in place on {self.exchange_name}"
)

await self._handle_missed_mirror_orders_fills(recently_closed_trades, missing_orders, current_price)
try:
# apply state and (re)create missing orders
Expand Down Expand Up @@ -515,10 +521,13 @@ def _get_origin_orders_count(self, recent_trades, open_orders):
origin_created_buy_orders_count = self.buy_orders_count
origin_created_sell_orders_count = self.sell_orders_count
if recent_trades:
# in case all initial orders didn't get created, try to infer the original value from open orders and trades
buy_orders_count = len([order for order in open_orders if order.side is trading_enums.TradeOrderSide.BUY])
buy_trades_count = len([trade for trade in recent_trades if trade.side is trading_enums.TradeOrderSide.BUY])
origin_created_buy_orders_count = buy_orders_count + buy_trades_count
origin_created_sell_orders_count = len(open_orders) + len(recent_trades) - origin_created_buy_orders_count
origin_created_sell_orders_count = (
len(open_orders) + len(recent_trades) - origin_created_buy_orders_count
)
return origin_created_buy_orders_count, origin_created_sell_orders_count

def _get_grid_trades_or_orders(self, trades_or_orders):
Expand Down
73 changes: 73 additions & 0 deletions Trading/Mode/grid_trading_mode/tests/test_grid_trading_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,79 @@ async def test_start_after_offline_x_filled_and_price_back_should_buy_to_recreat
_check_created_orders(producer, trading_api.get_open_orders(exchange_manager), 200)


async def test_start_after_offline_x_filled_and_missing_should_recreate_sell():
symbol = "BTC/USDT"
async with _get_tools(symbol) as (producer, _, exchange_manager):
# forced config
producer.buy_funds = producer.sell_funds = 0
producer.allow_order_funds_redispatch = True
producer.buy_orders_count = producer.sell_orders_count = 5
producer.compensate_for_missed_mirror_order = True
producer.enable_trailing_down = False
producer.enable_trailing_up = True
producer.flat_increment = decimal.Decimal(100)
producer.flat_spread = decimal.Decimal(300)
producer.reinvest_profits = False
producer.sell_volume_per_order = producer.buy_volume_per_order = False
producer.starting_price = 0
producer.use_existing_orders_only = False
producer.use_fixed_volume_for_mirror_orders = False

orders_count = producer.buy_orders_count + producer.sell_orders_count


initial_price = decimal.Decimal("105278.1")
trading_api.force_set_mark_price(exchange_manager, producer.symbol, initial_price)
btc_pf = trading_api.get_portfolio_currency(exchange_manager, "BTC")
usdt_pf = trading_api.get_portfolio_currency(exchange_manager, "USDT")
btc_pf.available = decimal.Decimal("0.00141858")
btc_pf.total = decimal.Decimal("0.00141858")
usdt_pf.available = decimal.Decimal("150.505098")
usdt_pf.total = decimal.Decimal("150.505098")

await producer._ensure_staggered_orders()
await asyncio.create_task(_check_open_orders_count(exchange_manager, orders_count))
original_orders = copy.copy(trading_api.get_open_orders(exchange_manager))
assert len(original_orders) == orders_count
assert sorted([
order.origin_price for order in original_orders
]) == [
# buy orders
decimal.Decimal('104728.1'), decimal.Decimal('104828.1'), decimal.Decimal('104928.1'),
decimal.Decimal('105028.1'), decimal.Decimal('105128.1'),
# sell orders
decimal.Decimal('105428.1'), decimal.Decimal('105528.1'), decimal.Decimal('105628.1'),
decimal.Decimal('105728.1'), decimal.Decimal('105828.1')
]

# price goes down to 105120, 105128.1 order gets filled
price = decimal.Decimal("105120")
# offline simulation: price goes down to 105120, 105128.1 order gets filled
offline_filled = [order for order in original_orders if order.origin_price == decimal.Decimal('105128.1')]
assert len(offline_filled) == 1
assert offline_filled[0].side == trading_enums.TradeOrderSide.BUY
for order in offline_filled:
await _fill_order(order, exchange_manager, trigger_update_callback=False, producer=producer)
assert len(trading_api.get_open_orders(exchange_manager)) == orders_count - len(offline_filled)
assert btc_pf.available == decimal.Decimal('0.00028861409')
assert btc_pf.total == decimal.Decimal('0.00170420409')
assert usdt_pf.available == decimal.Decimal('0.247225519')
assert usdt_pf.total == decimal.Decimal('120.447922929')

# back online: restore orders according to current price
trading_api.force_set_mark_price(exchange_manager, producer.symbol, price)
with _assert_missing_orders_count(producer, len(offline_filled)):
await producer._ensure_staggered_orders()
# restored orders
await asyncio.create_task(_check_open_orders_count(exchange_manager, orders_count))
open_orders = trading_api.get_open_orders(exchange_manager)
# there is now 6 sell orders
assert len([order for order in open_orders if order.side is trading_enums.TradeOrderSide.SELL]) == 6
# there is now 4 buy orders
assert len([order for order in open_orders if order.side is trading_enums.TradeOrderSide.BUY]) == 4
_check_created_orders(producer, trading_api.get_open_orders(exchange_manager), initial_price)


async def test_start_after_offline_1_filled_should_create_buy():
symbol = "BTC/USDT"
async with _get_tools(symbol) as (producer, _, exchange_manager):
Expand Down

0 comments on commit e37bf67

Please sign in to comment.