@@ -58,6 +58,7 @@ def __init__(self, config, exchange_manager):
58
58
if not hasattr (self , 'simulate' ):
59
59
self .simulate = False
60
60
self .is_enabled = self .__class__ .enabled (self .config )
61
+ self .enable_inactive_orders = not self .simulate
61
62
62
63
async def initialize_impl (self ):
63
64
self .is_enabled = self .is_enabled and self .exchange_manager .is_trading
@@ -72,6 +73,9 @@ def clear(self):
72
73
def enabled (cls , config ):
73
74
return util .is_trader_enabled (config )
74
75
76
+ def set_enable_inactive_orders (self , enabled : bool ):
77
+ self .enable_inactive_orders = enabled
78
+
75
79
def set_risk (self , risk ):
76
80
min_risk = decimal .Decimal (str (octobot_commons .constants .CONFIG_TRADER_RISK_MIN ))
77
81
max_risk = decimal .Decimal (str (octobot_commons .constants .CONFIG_TRADER_RISK_MAX ))
@@ -116,8 +120,7 @@ async def create_order(
116
120
try :
117
121
params = params or {}
118
122
self .logger .info (f"Creating order: { created_order } " )
119
- created_order = await self ._create_new_order (order , params , wait_for_creation = wait_for_creation ,
120
- creation_timeout = creation_timeout )
123
+ created_order = await self ._create_new_order (order , params , wait_for_creation , creation_timeout )
121
124
if created_order is None :
122
125
self .logger .warning (f"Order not created on { self .exchange_manager .exchange_name } "
123
126
f"(failed attempt to create: { order } ). This is likely due to "
@@ -186,7 +189,7 @@ async def edit_order(self, order,
186
189
disabled_state_updater = self .exchange_manager .exchange_personal_data \
187
190
.orders_manager .enable_order_auto_synchronization is False
188
191
# now that we got the lock, ensure we can edit the order
189
- if not self .simulate and not order .is_self_managed () and (
192
+ if not self .simulate and order . is_active and not order .is_self_managed () and (
190
193
order .state is not None or disabled_state_updater
191
194
):
192
195
if disabled_state_updater :
@@ -264,16 +267,18 @@ async def _edit_order_on_exchange(
264
267
await self .exchange_manager .exchange_personal_data .handle_portfolio_and_position_update_from_order (order )
265
268
return changed
266
269
267
- async def _create_new_order (self , new_order , params : dict ,
268
- wait_for_creation = True ,
269
- creation_timeout = octobot_trading . constants . INDIVIDUAL_ORDER_SYNC_TIMEOUT ) -> object :
270
+ async def _create_new_order (
271
+ self , new_order , params : dict , wait_for_creation : bool , creation_timeout : float
272
+ ) :
270
273
"""
271
274
Creates an exchange managed order, it might be a simulated or a real order.
272
275
Portfolio will be updated by the created order state after order will be initialized
273
276
"""
274
277
updated_order = new_order
275
278
is_pending_creation = False
276
- if not self .simulate and not new_order .is_self_managed ():
279
+ if not self .simulate and not new_order .is_self_managed () and (
280
+ new_order .is_in_active_inactive_transition or new_order .is_active
281
+ ):
277
282
order_params = self .exchange_manager .exchange .get_order_additional_params (new_order )
278
283
order_params .update (new_order .exchange_creation_params )
279
284
order_params .update (params )
@@ -313,18 +318,29 @@ async def _create_new_order(self, new_order, params: dict,
313
318
updated_order .associated_entry_ids = new_order .associated_entry_ids
314
319
updated_order .update_with_triggering_order_fees = new_order .update_with_triggering_order_fees
315
320
updated_order .trailing_profile = new_order .trailing_profile
321
+ updated_order .active_trigger_price = new_order .active_trigger_price
322
+ updated_order .active_trigger_above = new_order .active_trigger_above
323
+ updated_order .is_in_active_inactive_transition = new_order .is_in_active_inactive_transition
316
324
317
325
if is_pending_creation :
318
326
# register order as pending order, it will then be added to live orders in order manager once open
319
327
self .exchange_manager .exchange_personal_data .orders_manager .register_pending_creation_order (
320
328
updated_order
321
329
)
322
330
323
- await updated_order .initialize ()
324
- if is_pending_creation and wait_for_creation \
325
- and updated_order .state is not None and updated_order .state .is_pending ()\
326
- and self .exchange_manager .exchange_personal_data .orders_manager .enable_order_auto_synchronization :
327
- await updated_order .state .wait_for_terminate (creation_timeout )
331
+ try :
332
+ await updated_order .initialize ()
333
+ if is_pending_creation and wait_for_creation \
334
+ and updated_order .state is not None and updated_order .state .is_pending ()\
335
+ and self .exchange_manager .exchange_personal_data .orders_manager .enable_order_auto_synchronization :
336
+ await updated_order .state .wait_for_terminate (creation_timeout )
337
+ if new_order .is_in_active_inactive_transition :
338
+ # transition successful: new_order is now inactive
339
+ await new_order .on_active_from_inactive ()
340
+ finally :
341
+ if updated_order .is_in_active_inactive_transition :
342
+ # transition completed: never leave is_in_active_inactive_transition to True after transition
343
+ updated_order .is_in_active_inactive_transition = False
328
344
return updated_order
329
345
330
346
def get_take_profit_order_type (self , base_order , order_type : enums .TraderOrderType ) -> enums .TraderOrderType :
@@ -385,6 +401,36 @@ async def chain_order(self, order, chained_order, update_with_triggering_order_f
385
401
order .add_chained_order (chained_order )
386
402
self .logger .info (f"Added chained order [{ chained_order } ] to [{ order } ] order." )
387
403
404
+ async def update_order_as_inactive (
405
+ self , order , ignored_order = None , wait_for_cancelling = True ,
406
+ cancelling_timeout = octobot_trading .constants .INDIVIDUAL_ORDER_SYNC_TIMEOUT
407
+ ) -> bool :
408
+ if self .simulate :
409
+ self .logger .error (f"Can't update order as inactive on simulated trading." )
410
+ return False
411
+ cancelled = False
412
+ if order and order .is_open ():
413
+ with order .active_or_inactive_transition ():
414
+ cancelled = await self ._handle_order_cancellation (
415
+ order , ignored_order , wait_for_cancelling , cancelling_timeout
416
+ )
417
+ else :
418
+ self .logger .error (f"Can't update order as inactive: { order } is not open on exchange." )
419
+ return cancelled
420
+
421
+ async def update_order_as_active (
422
+ self , order , params : dict = None , wait_for_creation = True , raise_all_creation_error = False ,
423
+ creation_timeout = octobot_trading .constants .INDIVIDUAL_ORDER_SYNC_TIMEOUT
424
+ ):
425
+ if self .simulate :
426
+ self .logger .error (f"Can't update order as active on simulated trading." )
427
+ return order
428
+ with order .active_or_inactive_transition ():
429
+ return await self .create_order (
430
+ order , loaded = False , params = params , wait_for_creation = wait_for_creation ,
431
+ raise_all_creation_error = raise_all_creation_error , creation_timeout = creation_timeout
432
+ )
433
+
388
434
async def cancel_order (self , order , ignored_order = None ,
389
435
wait_for_cancelling = True ,
390
436
cancelling_timeout = octobot_trading .constants .INDIVIDUAL_ORDER_SYNC_TIMEOUT ) -> bool :
@@ -400,11 +446,12 @@ async def cancel_order(self, order, ignored_order=None,
400
446
:param cancelling_timeout: time before raising a timeout error when waiting for an order cancel
401
447
:return: None
402
448
"""
403
- if order and order .is_open ():
449
+ if order and order .is_open () or not order . is_active :
404
450
self .logger .info (f"Cancelling order: { order } " )
405
451
# always cancel this order first to avoid infinite loop followed by deadlock
406
- return await self ._handle_order_cancellation (order , ignored_order ,
407
- wait_for_cancelling , cancelling_timeout )
452
+ return await self ._handle_order_cancellation (
453
+ order , ignored_order , wait_for_cancelling , cancelling_timeout
454
+ )
408
455
return False
409
456
410
457
async def _handle_order_cancellation (
@@ -417,7 +464,7 @@ async def _handle_order_cancellation(
417
464
return success
418
465
order_status = None
419
466
# if real order: cancel on exchange
420
- if not self .simulate and not order .is_self_managed ():
467
+ if not self .simulate and order . is_active and not order .is_self_managed ():
421
468
try :
422
469
async with order .lock :
423
470
try :
0 commit comments