Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Modes] reduce_only chained orders when trading futures #1400

Merged
merged 1 commit into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Trading/Mode/daily_trading_mode/daily_trading.py
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,8 @@ async def _create_order(
chained_orders = []
is_long = current_order.side is trading_enums.TradeOrderSide.BUY
exit_side = trading_enums.TradeOrderSide.SELL if is_long else trading_enums.TradeOrderSide.BUY
# tag chained orders as reduce_only when trading futures
reduce_only_chained_orders = self.exchange_manager.is_future
if use_stop_loss_orders:
if len(stop_loss_details) > 1:
self.logger.error(f"Multiple stop loss orders is not supported.")
Expand All @@ -509,7 +511,8 @@ async def _create_order(
)
) if (not stop_loss_details or stop_loss_details[0].price.is_nan()) else stop_loss_details[0].price
param_update, chained_order = await self.register_chained_order(
current_order, stop_price, trading_enums.TraderOrderType.STOP_LOSS, exit_side, tag=tag
current_order, stop_price, trading_enums.TraderOrderType.STOP_LOSS, exit_side,
tag=tag, reduce_only=reduce_only_chained_orders
)
params.update(param_update)
chained_orders.append(chained_order)
Expand All @@ -536,7 +539,7 @@ async def _create_order(
)
param_update, chained_order = await self.register_chained_order(
current_order, take_profit_price, order_type, exit_side,
quantity=take_profits_detail.quantity, tag=tag
quantity=take_profits_detail.quantity, tag=tag, reduce_only=reduce_only_chained_orders
)
params.update(param_update)
chained_orders.append(chained_order)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,7 @@ async def test_chained_stop_loss_and_take_profit_orders(tools):
assert stop_order.is_waiting_for_chained_trigger is False
assert stop_order.associated_entry_ids == [buy_order.order_id]
assert stop_order.tag == "super"
assert stop_order.reduce_only is False
assert stop_order.is_open()

state = trading_enums.EvaluatorStates.LONG.value
Expand All @@ -978,6 +979,7 @@ async def test_chained_stop_loss_and_take_profit_orders(tools):
assert take_profit_order.associated_entry_ids == [buy_order.order_id]
assert not take_profit_order.is_open()
assert not take_profit_order.is_created()
assert take_profit_order.reduce_only is False
# take profit only using ADDITIONAL_TAKE_PROFIT_PRICES_KEY
data = {
consumer.ADDITIONAL_TAKE_PROFIT_PRICES_KEY: [decimal.Decimal("100000")],
Expand All @@ -995,6 +997,7 @@ async def test_chained_stop_loss_and_take_profit_orders(tools):
assert take_profit_order.associated_entry_ids == [buy_order.order_id]
assert not take_profit_order.is_open()
assert not take_profit_order.is_created()
assert take_profit_order.reduce_only is False

# stop loss and take profit
data = {
Expand Down Expand Up @@ -1023,6 +1026,7 @@ async def test_chained_stop_loss_and_take_profit_orders(tools):
assert take_profit_order.associated_entry_ids == [buy_order.order_id]
assert not take_profit_order.is_open()
assert not take_profit_order.is_created()
assert take_profit_order.reduce_only is False
assert isinstance(stop_order.order_group, trading_personal_data.OneCancelsTheOtherOrderGroup)
assert take_profit_order.order_group is stop_order.order_group

Expand All @@ -1044,6 +1048,7 @@ async def test_chained_stop_loss_and_take_profit_orders(tools):
assert sell_limit.chained_orders == []
assert stop_loss.associated_entry_ids is None
assert stop_loss.chained_orders == []
assert stop_loss.reduce_only is True # True as force stop loss
assert stop_loss.origin_price == decimal.Decimal("123")
assert stop_loss.origin_quantity == decimal.Decimal("0.01") \
- trading_personal_data.get_fees_for_currency(sell_limit.fee, stop_loss.quantity_currency)
Expand Down Expand Up @@ -1207,6 +1212,7 @@ async def test_target_profit_mode(tools):
assert isinstance(take_profit_order, trading_personal_data.SellLimitOrder)
assert take_profit_order.side is trading_enums.TradeOrderSide.SELL
assert take_profit_order.origin_quantity == buy_order.origin_quantity
assert take_profit_order.reduce_only is False
assert take_profit_order.origin_price == trading_personal_data.decimal_adapt_price(
symbol_market,
buy_order.origin_price * (trading_constants.ONE + consumer.TARGET_PROFIT_TAKE_PROFIT)
Expand All @@ -1225,6 +1231,7 @@ async def test_target_profit_mode(tools):
assert isinstance(stop_order, trading_personal_data.StopLossOrder)
assert stop_order.side is trading_enums.TradeOrderSide.SELL
assert stop_order.origin_quantity == buy_order.origin_quantity
assert stop_order.reduce_only is False
assert stop_order.origin_price == trading_personal_data.decimal_adapt_price(
symbol_market,
buy_order.origin_price * (trading_constants.ONE - consumer.TARGET_PROFIT_STOP_LOSS)
Expand Down Expand Up @@ -1307,12 +1314,14 @@ async def test_target_profit_mode_futures_trading(future_tools):
assert isinstance(stop_loss_order, trading_personal_data.StopLossOrder)
assert take_profit_order.side is trading_enums.TradeOrderSide.BUY
assert take_profit_order.origin_quantity == sell_order.origin_quantity
assert take_profit_order.reduce_only is True
assert take_profit_order.origin_price == trading_personal_data.decimal_adapt_price(
symbol_market,
sell_order.origin_price * (trading_constants.ONE - consumer.TARGET_PROFIT_TAKE_PROFIT)
)
assert stop_loss_order.side is trading_enums.TradeOrderSide.BUY
assert stop_loss_order.origin_quantity == sell_order.origin_quantity
assert stop_loss_order.reduce_only is True
assert stop_loss_order.origin_price == trading_personal_data.decimal_adapt_price(
symbol_market,
sell_order.origin_price * (trading_constants.ONE + consumer.TARGET_PROFIT_STOP_LOSS)
Expand Down
7 changes: 5 additions & 2 deletions Trading/Mode/dca_trading_mode/dca_trading.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,14 +367,16 @@ async def _create_entry_with_chained_exit_orders(self, entry_order, entry_price,
symbol_market
)
can_bundle_exit_orders = len(exit_quantities) == 1
reduce_only_chained_orders = self.exchange_manager.is_future
for i, exit_quantity in exit_quantities:
order_couple = []
# stop loss
if self.trading_mode.use_stop_loss:
stop_price = trading_personal_data.decimal_adapt_price(symbol_market, stop_price)
param_update, chained_order = await self.register_chained_order(
entry_order, stop_price, trading_enums.TraderOrderType.STOP_LOSS, exit_side,
quantity=exit_quantity, allow_bundling=can_bundle_exit_orders
quantity=exit_quantity, allow_bundling=can_bundle_exit_orders,
reduce_only=reduce_only_chained_orders
)
params.update(param_update)
order_couple.append(chained_order)
Expand All @@ -399,7 +401,8 @@ async def _create_entry_with_chained_exit_orders(self, entry_order, entry_price,
)
param_update, chained_order = await self.register_chained_order(
entry_order, take_profit_price, take_profit_order_type, None,
quantity=exit_quantity, allow_bundling=can_bundle_exit_orders
quantity=exit_quantity, allow_bundling=can_bundle_exit_orders,
reduce_only=reduce_only_chained_orders
)
params.update(param_update)
order_couple.append(chained_order)
Expand Down
6 changes: 5 additions & 1 deletion Trading/Mode/dca_trading_mode/tests/test_dca_trading_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ async def test_create_entry_with_chained_exit_orders(tools):
assert stop_loss.origin_price == entry_price * (1 - mode.stop_loss_price_multiplier)
assert stop_loss.triggered_by is entry_order
assert stop_loss.order_group is None
assert stop_loss.reduce_only is False
# reset values
create_order_mock.reset_mock()
entry_order.chained_orders = []
Expand All @@ -456,6 +457,7 @@ async def test_create_entry_with_chained_exit_orders(tools):
assert take_profit.origin_price == entry_price * (1 + mode.exit_limit_orders_price_multiplier)
assert take_profit.triggered_by is entry_order
assert take_profit.order_group is None
assert take_profit.reduce_only is False
# reset values
create_order_mock.reset_mock()
entry_order.chained_orders = []
Expand Down Expand Up @@ -531,7 +533,8 @@ async def test_create_entry_with_chained_exit_orders(tools):
create_order_mock.reset_mock()
entry_order.chained_orders = []

# chained stop loss
# chained stop loss on futures
consumer.exchange_manager.is_future = True
# 3 take profit (initial + 2 additional)
mode.use_stop_loss = True
mode.use_take_profit_exit_orders = True
Expand All @@ -555,6 +558,7 @@ async def test_create_entry_with_chained_exit_orders(tools):
# ensure only stop losses and take profits in chained orders
assert len(stop_losses) == 1
assert len(take_profits) == 1
assert all(order.reduce_only is True for order in entry_order.chained_orders) # futures: use reduce only
assert stop_losses[0].origin_quantity == take_profits[0].origin_quantity == entry_order.origin_quantity


Expand Down
Loading