-
Notifications
You must be signed in to change notification settings - Fork 58
Inactive orders #1206
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
base: master
Are you sure you want to change the base?
Inactive orders #1206
Conversation
550972c
to
2a0f2cf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great implementation!
if self.simulate: | ||
self.logger.error(f"Can't update order as inactive on simulated trading.") | ||
return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we check self.enable_inactive_orders
instead self.simulate
here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indeed!
self.is_active = True # When is_active=False order is not pushed to exchanges | ||
self.active_trigger_price: decimal.Decimal = None # price threshold from which the order becomes active | ||
# when True, order becomes active when current price >= active_trigger_price | ||
self.active_trigger_above: bool = None | ||
self._active_trigger_event: asyncio.Event = None # will be set when the price is hit | ||
# waiter that will call on_active_trigger() when active_trigger_event is set | ||
self._active_trigger_task: asyncio.Task = None | ||
# True when a transition between active and inactive is being made | ||
self.is_in_active_inactive_transition = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should create an ActiveState or something like this to manage all attributes and functions related to order activeness. I think it will be easier to abstract the activeness logic inside a dedicated class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in order.active_trigger
using the new PriceTrigger
class
ab80116
to
f773a3c
Compare
def create_or_update_active_trigger(self, active_trigger_price: decimal.Decimal, active_trigger_above: bool): | ||
if self.active_trigger is None: | ||
self.active_trigger = price_trigger.PriceTrigger( | ||
self.on_active_trigger, (None, None), active_trigger_price, active_trigger_above | ||
) | ||
else: | ||
self.active_trigger.trigger_price = active_trigger_price | ||
self.active_trigger.trigger_above = active_trigger_above | ||
|
||
async def set_as_inactive(self, active_trigger_price: decimal.Decimal, active_trigger_above: bool): | ||
""" | ||
Marks the instance as inactive and ensures the inactive order watcher is scheduled. | ||
""" | ||
if active_trigger_price is None or active_trigger_above is None: | ||
raise ValueError( | ||
f"Both active_trigger_price and active_trigger_above must be provided to set an order as inactive" | ||
) | ||
logging.get_logger(self.get_logger_name()).info("Order is switching to inactive") | ||
self.is_active = False | ||
self.create_or_update_active_trigger(active_trigger_price, active_trigger_above) | ||
# enforce attributes in case order has been canceled | ||
self.status = enums.OrderStatus.OPEN | ||
self.canceled_time = 0 | ||
await self._ensure_inactive_order_watcher() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is consistent with the trigger architecture. I believe Order should only be able to add/update a trigger but not create it. In other words, it should not take an 'active_trigger_price' argument but only an 'active_trigger,' and it’s the responsibility of the caller to provide the instance of the correct trigger class based on what is desired.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point, i'll update this, thanks !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's up
import octobot_trading.personal_data.orders.triggers.base_trigger as base_trigger | ||
|
||
|
||
class PriceTrigger(base_trigger.BaseTrigger): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
f773a3c
to
bd6b3a0
Compare
finally: | ||
self.is_in_active_inactive_transition = previous_value | ||
|
||
def use_active_trigger(self, active_trigger: price_trigger.PriceTrigger): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def use_active_trigger(self, active_trigger: price_trigger.PriceTrigger): | |
def use_active_trigger(self, active_trigger: base_trigger.BaseTrigger): |
self.active_trigger.trigger_price = active_trigger.trigger_price | ||
self.active_trigger.trigger_above = active_trigger.trigger_above | ||
|
||
async def set_as_inactive(self, active_trigger: price_trigger.PriceTrigger): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
async def set_as_inactive(self, active_trigger: price_trigger.PriceTrigger): | |
async def set_as_inactive(self, active_trigger: base_trigger.BaseTrigger): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indeed, it's up, I also added unit tests.
bd6b3a0
to
bb61376
Compare
bb61376
to
3db76c7
Compare
3db76c7
to
4e5a8ab
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great feature!
def test_is_pending_when_not_initialized(trigger): | ||
assert not trigger.is_pending() | ||
|
||
def test_str_representation(trigger): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😄
No description provided.