Skip to content

Commit

Permalink
Merge pull request #193 from alpacahq/change_can_trade_check
Browse files Browse the repository at this point in the history
Changed the "can_trade" check to be more resilient.
now only check if:
- api says asset is tradable
- calendar says it's a valid session
  • Loading branch information
Shlomi Kushchi authored Sep 18, 2020
2 parents 6eed3cc + 46fddb9 commit f1f5430
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 15 deletions.
46 changes: 33 additions & 13 deletions pylivetrader/data/bardata.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
# limitations under the License.
import pandas
import pandas as pd
import numpy as np

from contextlib import contextmanager
from collections import Iterable
Expand Down Expand Up @@ -246,14 +245,24 @@ def _can_trade_for_asset(self, asset, dt, adjusted_dt, data_portal):
# if self._is_restricted(asset, adjusted_dt):
# return False

session_label = self.calendar.minute_to_session_label(dt)

if not asset.is_alive_for_session(session_label):
# asset isn't alive
if not self.data_portal.backend._api.get_asset(asset.symbol).tradable:
return False

if asset.auto_close_date and session_label >= asset.auto_close_date:
return False
# this sometimes fail even though the asset is trade-able. I cancelled
# this check, and added the one above it

# session_label = self.calendar.minute_to_session_label(dt)
# if not asset.is_alive_for_session(session_label):
# # asset isn't alive
# return False

# this condition is being commented out because of the asset VXX
# as it turns out, there are 2 VXX assets in the Alpaca asset list.
# one is tradable, one is not. the auto_close_date is set (first for
# the tradable one then for the not tradable one, casuing this to fail
# it's set in alpaca.backend.get_equities() (asset.end_date)
# if asset.auto_close_date and session_label >= asset.auto_close_date:
# return False

if not self._daily_mode:
# Find the next market minute for this calendar, and check if this
Expand All @@ -267,12 +276,23 @@ def _can_trade_for_asset(self, asset, dt, adjusted_dt, data_portal):
if not asset.is_exchange_open(dt_to_use_for_exchange_check):
return False

# is there a last price?
return not np.isnan(
data_portal.get_spot_value(
asset, "price", adjusted_dt, self.data_frequency
)
)
# spot value doesn't always exist even though the asset is trade-able
# you could get previous prices by doing
# data_portal.get_history_window([Equity("AAPL", "NYSE")],
# adjusted_dt, 120, 'minute',
# 'price', '1m')
# but it won't always contain the lasy minute.
# I will not fail the "can_trade" method for that, and will allow the
# user the option to try trading even though, spot price doesn't exist

# # is there a last price?
# return not np.isnan(
# data_portal.get_spot_value(
# asset, "price", adjusted_dt, self.data_frequency
# )
# )

return True

def is_stale(self, assets):
"""
Expand Down
13 changes: 13 additions & 0 deletions pylivetrader/testing/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ def create_bars(minutes, offset):
}, index=minutes)


class MockAsset:
@property
def tradable(self):
return True


class AlpacaApi:
@staticmethod
def get_asset(sym):
return MockAsset()


class Backend:

def __init__(self, start=None, end=None, assets=None, exchange='NYSE'):
Expand All @@ -37,6 +49,7 @@ def __init__(self, start=None, end=None, assets=None, exchange='NYSE'):

self._exchange = exchange
self._calendar = get_calendar(exchange)
self._api = AlpacaApi()

self.assets = assets or ['asset-0', 'asset-1', 'asset-2']

Expand Down
4 changes: 2 additions & 2 deletions tests/test_data/test_bardata.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def test_bardata():
assert data.can_trade(asset_to_check)
assert not data.is_stale(asset_to_check)

data.datetime = pd.Timestamp('2018-08-14', tz='UTC')
assert not data.can_trade(asset_to_check)
# data.datetime = pd.Timestamp('2018-08-14', tz='UTC')
# assert not data.can_trade(asset_to_check)
# when asset is not tradable, return false
assert not data.is_stale(asset_to_check)

0 comments on commit f1f5430

Please sign in to comment.