From dc4c76d309b3f5252847ecefa0d3d6b5bb5d9349 Mon Sep 17 00:00:00 2001 From: ttt733 Date: Fri, 9 Nov 2018 15:30:07 -0800 Subject: [PATCH 1/6] older orders should no longer be ignored --- pylivetrader/backend/alpaca.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pylivetrader/backend/alpaca.py b/pylivetrader/backend/alpaca.py index 76fb039..86f338b 100644 --- a/pylivetrader/backend/alpaca.py +++ b/pylivetrader/backend/alpaca.py @@ -282,10 +282,7 @@ def order(self, asset, amount, style): @property def orders(self): - return { - o.client_order_id: self._order2zp(o) - for o in self._api.list_orders('all') - } + return self.all_orders() def all_orders(self, before=None, status='all'): until = pd.Timestamp.utcnow().isoformat() if before is None else before From 7aaa96c4b9b37865dca105439654ccb5416b69dc Mon Sep 17 00:00:00 2001 From: ttt733 Date: Mon, 12 Nov 2018 01:17:15 -0600 Subject: [PATCH 2/6] improved filtering of get_all_orders output --- pylivetrader/algorithm.py | 19 ++++++++++++++----- pylivetrader/backend/alpaca.py | 29 ++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/pylivetrader/algorithm.py b/pylivetrader/algorithm.py index 28a70a0..541533c 100644 --- a/pylivetrader/algorithm.py +++ b/pylivetrader/algorithm.py @@ -613,7 +613,14 @@ def get_open_orders(self, asset=None): return self.get_all_orders(asset=asset, status='open') @api_method - def get_all_orders(self, asset=None, before=None, status='all'): + def get_recent_orders(self, days_back=2): + ''' + Returns all orders from the past n days. + ''' + return self.get_all_orders(days_back=days_back) + + @api_method + def get_all_orders(self, asset=None, before=None, status='all', days_back=None): ''' If asset is unspecified or None, returns a dictionary keyed by asset ID. The dictionary contains a list of orders for each ID, @@ -622,7 +629,7 @@ def get_all_orders(self, asset=None, before=None, status='all'): before will not be returned. If provided, only orders of type status ('closed' or 'open') will be returned. ''' - orders = self._backend.all_orders(before, status) + orders = self._backend.all_orders(before, status, days_back) omap = {} orders = sorted([ @@ -640,9 +647,11 @@ def get_all_orders(self, asset=None, before=None, status='all'): @api_method def get_order(self, order_id): - orders = self._backend.orders - if order_id in orders: - return orders[order_id].to_api_obj() + return self._backend.get_order(order_id) + + @api_method + def get_recent_orders(self, days_back=2): + return self._backend.recent_orders @api_method def cancel_order(self, order_param): diff --git a/pylivetrader/backend/alpaca.py b/pylivetrader/backend/alpaca.py index 86f338b..b952e9b 100644 --- a/pylivetrader/backend/alpaca.py +++ b/pylivetrader/backend/alpaca.py @@ -282,19 +282,30 @@ def order(self, asset, amount, style): @property def orders(self): - return self.all_orders() - - def all_orders(self, before=None, status='all'): - until = pd.Timestamp.utcnow().isoformat() if before is None else before + return { + o.client_order_id: self._order2zp(o) + for o in self._api.list_orders('all') + } + + def get_order(self, zp_order_id): + return self._api.get_order_by_client_order_id(zp_order_id) + + def all_orders(self, before=None, status='all', days_back=None): + # Get all orders submitted days_back days before 'before'. + start = pd.Timestamp.utcnow().isoformat() if before is None else before + until = start all_orders = {} batch_size = 500 orders = self._api.list_orders(status, batch_size, until=until) while len(orders) > 0: - batch_orders = { - o.client_order_id: self._order2zp(o) - for o in orders - } - # get the timestamp of the earliest order in the batch + batch_orders = {} + for order in batch_orders: + days_since_order = (start - order.submitted_at).days + if days_back is not None and days_since_order > days_back: + all_orders.update(batch_orders) + break + batch_orders[order.client_order_id] = self._order2zp(order) + # Get the timestamp of the earliest order in the batch. until = pd.Timestamp(orders[-1].submitted_at).isoformat() all_orders.update(batch_orders) orders = self._api.list_orders(status, batch_size, until=until) From 8d79531056965919045672bf600d59edfab2565e Mon Sep 17 00:00:00 2001 From: ttt733 Date: Mon, 12 Nov 2018 01:20:25 -0600 Subject: [PATCH 3/6] flake8 fixes --- pylivetrader/algorithm.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pylivetrader/algorithm.py b/pylivetrader/algorithm.py index 541533c..389b807 100644 --- a/pylivetrader/algorithm.py +++ b/pylivetrader/algorithm.py @@ -620,7 +620,12 @@ def get_recent_orders(self, days_back=2): return self.get_all_orders(days_back=days_back) @api_method - def get_all_orders(self, asset=None, before=None, status='all', days_back=None): + def get_all_orders( + self, + asset=None, + before=None, + status='all', + days_back=None): ''' If asset is unspecified or None, returns a dictionary keyed by asset ID. The dictionary contains a list of orders for each ID, @@ -649,10 +654,6 @@ def get_all_orders(self, asset=None, before=None, status='all', days_back=None): def get_order(self, order_id): return self._backend.get_order(order_id) - @api_method - def get_recent_orders(self, days_back=2): - return self._backend.recent_orders - @api_method def cancel_order(self, order_param): order_id = order_param From b2eb115cff3bd006b8b680f356c6d63856f46873 Mon Sep 17 00:00:00 2001 From: ttt733 Date: Mon, 12 Nov 2018 14:37:20 -0600 Subject: [PATCH 4/6] addressing code review comments --- pylivetrader/algorithm.py | 2 +- pylivetrader/backend/alpaca.py | 39 ++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/pylivetrader/algorithm.py b/pylivetrader/algorithm.py index 389b807..96632ae 100644 --- a/pylivetrader/algorithm.py +++ b/pylivetrader/algorithm.py @@ -652,7 +652,7 @@ def get_all_orders( @api_method def get_order(self, order_id): - return self._backend.get_order(order_id) + return self._backend.get_order(order_id).to_api_obj() @api_method def cancel_order(self, order_param): diff --git a/pylivetrader/backend/alpaca.py b/pylivetrader/backend/alpaca.py index b952e9b..7640ae4 100644 --- a/pylivetrader/backend/alpaca.py +++ b/pylivetrader/backend/alpaca.py @@ -288,27 +288,44 @@ def orders(self): } def get_order(self, zp_order_id): - return self._api.get_order_by_client_order_id(zp_order_id) + return self._order2zp( + self._api.get_order_by_client_order_id(zp_order_id) + ) def all_orders(self, before=None, status='all', days_back=None): - # Get all orders submitted days_back days before 'before'. + # Get all orders submitted days_back days before `before`. start = pd.Timestamp.utcnow().isoformat() if before is None else before + + # A session label refers to the market date that an order submitted + # at a given minute would be executed on. We'll need to keep track of + # this if the function is bounded by days_back. + start_session_label = self._cal.minute_to_session_label(start) + reached_end_date = False + until = start all_orders = {} batch_size = 500 + orders = self._api.list_orders(status, batch_size, until=until) - while len(orders) > 0: + while len(orders) > 0 and not reached_end_date: batch_orders = {} - for order in batch_orders: - days_since_order = (start - order.submitted_at).days - if days_back is not None and days_since_order > days_back: - all_orders.update(batch_orders) - break + for order in orders: + if days_back is not None: + # Verify that the order is not too old. + # `session_distance()` ignores holidays and weekends. + days_since_order = self._cal.session_distance( + self._cal.minute_to_session_label(order.submitted_at), + start_session_label + ) + if days_since_order > days_back: + reached_end_date = True + break batch_orders[order.client_order_id] = self._order2zp(order) - # Get the timestamp of the earliest order in the batch. - until = pd.Timestamp(orders[-1].submitted_at).isoformat() all_orders.update(batch_orders) - orders = self._api.list_orders(status, batch_size, until=until) + if not reached_end_date: + # Get the timestamp of the earliest order in the batch. + until = pd.Timestamp(orders[-1].submitted_at).isoformat() + orders = self._api.list_orders(status, batch_size, until=until) return all_orders def cancel_order(self, zp_order_id): From 854bea6bbd007608250e45b2297ec81f4424bd53 Mon Sep 17 00:00:00 2001 From: ttt733 Date: Mon, 12 Nov 2018 14:41:13 -0600 Subject: [PATCH 5/6] removing unnecessary variable --- pylivetrader/backend/alpaca.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pylivetrader/backend/alpaca.py b/pylivetrader/backend/alpaca.py index 7640ae4..c39764e 100644 --- a/pylivetrader/backend/alpaca.py +++ b/pylivetrader/backend/alpaca.py @@ -302,11 +302,10 @@ def all_orders(self, before=None, status='all', days_back=None): start_session_label = self._cal.minute_to_session_label(start) reached_end_date = False - until = start all_orders = {} batch_size = 500 - orders = self._api.list_orders(status, batch_size, until=until) + orders = self._api.list_orders(status, batch_size, until=start) while len(orders) > 0 and not reached_end_date: batch_orders = {} for order in orders: From 5824e838762a6dc71b946bdb061f2964b3e0763e Mon Sep 17 00:00:00 2001 From: ttt733 Date: Mon, 12 Nov 2018 16:26:35 -0600 Subject: [PATCH 6/6] fixing issue with passing trading_calendars isoformat() strings --- pylivetrader/backend/alpaca.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pylivetrader/backend/alpaca.py b/pylivetrader/backend/alpaca.py index c39764e..5cb0d1b 100644 --- a/pylivetrader/backend/alpaca.py +++ b/pylivetrader/backend/alpaca.py @@ -293,8 +293,9 @@ def get_order(self, zp_order_id): ) def all_orders(self, before=None, status='all', days_back=None): - # Get all orders submitted days_back days before `before`. - start = pd.Timestamp.utcnow().isoformat() if before is None else before + # Get all orders submitted days_back days before `before` or now. + now = pd.Timestamp.utcnow() + start = now.isoformat() if before is None else before.isoformat() # A session label refers to the market date that an order submitted # at a given minute would be executed on. We'll need to keep track of