Skip to content

Commit bf02b2b

Browse files
authored
Updating existing crypto APIs to v1beta2 and adding in Latest Orderbooks (#650)
* Updating crypto endpoints to v1beta2 * Removing files accidentally committed * Changing streaming version to v1beta2 * Fixing issue with mismatching keys in responses * Adding in single-symbol orderbooks method * Removing crypto XBBOs and exchange parameter * Deleted v1beta1 functions with exchanges parameter
1 parent 48aa8a9 commit bf02b2b

File tree

3 files changed

+65
-105
lines changed

3 files changed

+65
-105
lines changed

alpaca_trade_api/entity_v2.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,17 @@ def __init__(self, raw):
249249
self.asks[i] = BidOrAsk(self.asks[i])
250250

251251

252+
class OrderbooksV2(dict):
253+
def __init__(self, raw):
254+
for k, v in raw.items():
255+
for side in orderbook_mapping_v2.keys():
256+
if side not in v: continue
257+
readable_side = orderbook_mapping_v2[side]
258+
v[readable_side] = v[side]
259+
v.pop(side)
260+
self[k] = _convert_or_none(OrderbookV2, v)
261+
262+
252263
class NewsV2(Entity):
253264
def __init__(self, raw):
254265
super().__init__(raw)

alpaca_trade_api/rest.py

Lines changed: 53 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from .entity_v2 import (
2121
BarV2, BarsV2, LatestBarsV2, LatestQuotesV2, LatestTradesV2,
2222
SnapshotV2, SnapshotsV2, TradesV2, TradeV2, QuotesV2, QuoteV2,
23-
NewsV2, NewsListV2
23+
NewsV2, NewsListV2, OrderbookV2, OrderbooksV2
2424
)
2525

2626
logger = logging.getLogger(__name__)
@@ -562,8 +562,9 @@ def _data_get(self,
562562
page_token = None
563563
total_items = 0
564564
limit = kwargs.get('limit')
565+
is_multi_symbol = not isinstance(symbol_or_symbols, str)
565566
if resp_grouped_by_symbol is None:
566-
resp_grouped_by_symbol = not isinstance(symbol_or_symbols, str)
567+
resp_grouped_by_symbol = is_multi_symbol
567568
while True:
568569
actual_limit = None
569570
if limit:
@@ -573,11 +574,11 @@ def _data_get(self,
573574
data = kwargs
574575
data['limit'] = actual_limit
575576
data['page_token'] = page_token
576-
path = f'/{endpoint_base}'
577-
if isinstance(symbol_or_symbols, str) and symbol_or_symbols:
577+
path = f'/{endpoint_base}'
578+
if api_version == 'v1beta2' or is_multi_symbol:
579+
data['symbols'] = _join_with_commas(symbol_or_symbols)
580+
elif symbol_or_symbols:
578581
path += f'/{symbol_or_symbols}'
579-
else:
580-
data['symbols'] = ','.join(symbol_or_symbols)
581582
if asof:
582583
data['asof'] = asof
583584
if endpoint:
@@ -789,12 +790,10 @@ def get_crypto_trades_iter(self,
789790
start: Optional[str] = None,
790791
end: Optional[str] = None,
791792
limit: int = None,
792-
exchanges: Optional[List[str]] = None,
793793
raw=False) -> TradeIterator:
794794
trades = self._data_get('trades', symbol,
795-
api_version='v1beta1', endpoint_base='crypto',
796-
start=start, end=end, limit=limit,
797-
exchanges=exchanges)
795+
api_version='v1beta2', endpoint_base='crypto',
796+
start=start, end=end, limit=limit)
798797
for trade in trades:
799798
if raw:
800799
yield trade
@@ -805,23 +804,19 @@ def get_crypto_trades(self,
805804
symbol: str,
806805
start: Optional[str] = None,
807806
end: Optional[str] = None,
808-
limit: int = None,
809-
exchanges: Optional[List[str]] = None,
810-
) -> TradesV2:
807+
limit: int = None) -> TradesV2:
811808
return TradesV2(list(self.get_crypto_trades_iter(
812-
symbol, start, end, limit, exchanges, raw=True)))
809+
symbol, start, end, limit, raw=True)))
813810

814811
def get_crypto_quotes_iter(self,
815812
symbol: str,
816813
start: Optional[str] = None,
817814
end: Optional[str] = None,
818815
limit: int = None,
819-
exchanges: Optional[List[str]] = None,
820816
raw=False) -> QuoteIterator:
821817
quotes = self._data_get('quotes', symbol,
822-
api_version='v1beta1', endpoint_base='crypto',
823-
start=start, end=end, limit=limit,
824-
exchanges=exchanges)
818+
api_version='v1beta2', endpoint_base='crypto',
819+
start=start, end=end, limit=limit)
825820
for quote in quotes:
826821
if raw:
827822
yield quote
@@ -832,25 +827,21 @@ def get_crypto_quotes(self,
832827
symbol: str,
833828
start: Optional[str] = None,
834829
end: Optional[str] = None,
835-
limit: int = None,
836-
exchanges: Optional[List[str]] = None,
837-
) -> QuotesV2:
830+
limit: int = None) -> QuotesV2:
838831
return QuotesV2(list(self.get_crypto_quotes_iter(
839-
symbol, start, end, limit, exchanges, raw=True)))
832+
symbol, start, end, limit, raw=True)))
840833

841834
def get_crypto_bars_iter(self,
842835
symbol: Union[str, List[str]],
843836
timeframe: TimeFrame,
844837
start: Optional[str] = None,
845838
end: Optional[str] = None,
846839
limit: int = None,
847-
exchanges: Optional[List[str]] = None,
848840
raw=False) -> BarIterator:
849841
bars = self._data_get('bars', symbol,
850-
api_version='v1beta1', endpoint_base='crypto',
842+
api_version='v1beta2', endpoint_base='crypto',
851843
timeframe=timeframe,
852-
start=start, end=end, limit=limit,
853-
exchanges=exchanges)
844+
start=start, end=end, limit=limit)
854845
for bar in bars:
855846
if raw:
856847
yield bar
@@ -862,101 +853,59 @@ def get_crypto_bars(self,
862853
timeframe: TimeFrame,
863854
start: Optional[str] = None,
864855
end: Optional[str] = None,
865-
limit: int = None,
866-
exchanges: Optional[List[str]] = None,
867-
) -> BarsV2:
856+
limit: int = None) -> BarsV2:
868857
return BarsV2(list(self.get_crypto_bars_iter(
869-
symbol, timeframe, start, end, limit, exchanges, raw=True)))
870-
871-
def get_latest_crypto_bar(self, symbol: str, exchange: str) -> BarV2:
872-
resp = self.data_get(
873-
'/crypto/{}/bars/latest'.format(symbol),
874-
data={'exchange': exchange},
875-
api_version='v1beta1')
876-
return self.response_wrapper(resp['bar'], BarV2)
858+
symbol, timeframe, start, end, limit, raw=True)))
877859

878-
def get_latest_crypto_bars(self,
879-
symbols: List[str],
880-
exchange: str) -> LatestBarsV2:
860+
def get_latest_crypto_bars(self, symbols: List[str]) -> LatestBarsV2:
881861
resp = self.data_get(
882-
'/crypto/bars/latest',
883-
data={'exchange': exchange, 'symbols': _join_with_commas(symbols)},
884-
api_version='v1beta1')
862+
'/crypto/latest/bars',
863+
data={'symbols': _join_with_commas(symbols)},
864+
api_version='v1beta2')
885865
return self.response_wrapper(resp['bars'], LatestBarsV2)
886866

887-
def get_latest_crypto_trade(self, symbol: str, exchange: str) -> TradeV2:
867+
def get_latest_crypto_trades(self, symbols: List[str]) -> LatestTradesV2:
888868
resp = self.data_get(
889-
'/crypto/{}/trades/latest'.format(symbol),
890-
data={'exchange': exchange},
891-
api_version='v1beta1')
892-
return self.response_wrapper(resp['trade'], TradeV2)
893-
894-
def get_latest_crypto_trades(self,
895-
symbols: List[str],
896-
exchange: str) -> LatestTradesV2:
897-
resp = self.data_get(
898-
'/crypto/trades/latest',
899-
data={'exchange': exchange, 'symbols': _join_with_commas(symbols)},
900-
api_version='v1beta1')
869+
'/crypto/latest/trades',
870+
data={'symbols': _join_with_commas(symbols)},
871+
api_version='v1beta2')
901872
return self.response_wrapper(resp['trades'], LatestTradesV2)
902873

903-
def get_latest_crypto_quote(self, symbol: str, exchange: str) -> QuoteV2:
904-
resp = self.data_get(
905-
'/crypto/{}/quotes/latest'.format(symbol),
906-
data={'exchange': exchange},
907-
api_version='v1beta1')
908-
return self.response_wrapper(resp['quote'], QuoteV2)
909-
910-
def get_latest_crypto_quotes(self,
911-
symbols: List[str],
912-
exchange: str) -> LatestQuotesV2:
874+
def get_latest_crypto_quotes(self, symbols: List[str]) -> LatestQuotesV2:
913875
resp = self.data_get(
914-
'/crypto/quotes/latest',
915-
data={'exchange': exchange, 'symbols': _join_with_commas(symbols)},
916-
api_version='v1beta1')
876+
'/crypto/latest/quotes',
877+
data={'symbols': _join_with_commas(symbols)},
878+
api_version='v1beta2')
917879
return self.response_wrapper(resp['quotes'], LatestQuotesV2)
918880

919-
def get_latest_crypto_xbbo(self,
920-
symbol: str,
921-
exchanges: Optional[List[str]] = None,
922-
) -> QuoteV2:
923-
params = {}
924-
if exchanges:
925-
params['exchanges'] = _join_with_commas(exchanges)
926-
resp = self.data_get(
927-
'/crypto/{}/xbbo/latest'.format(symbol),
928-
data=params,
929-
api_version='v1beta1')
930-
return self.response_wrapper(resp['xbbo'], QuoteV2)
931-
932-
def get_latest_crypto_xbbos(self,
933-
symbols: List[str],
934-
exchanges: Optional[List[str]] = None,
935-
) -> QuoteV2:
936-
params = {'symbols': _join_with_commas(symbols)}
937-
if exchanges:
938-
params['exchanges'] = _join_with_commas(exchanges)
881+
def get_crypto_snapshot(self, symbols: str) -> SnapshotsV2:
939882
resp = self.data_get(
940-
'/crypto/xbbos/latest',
941-
data=params,
942-
api_version='v1beta1')
943-
return self.response_wrapper(resp['xbbos'], QuotesV2)
944-
945-
def get_crypto_snapshot(self, symbol: str, exchange: str) -> SnapshotV2:
946-
resp = self.data_get('/crypto/{}/snapshot'.format(symbol),
947-
data={'exchange': exchange},
948-
api_version='v1beta1')
949-
return self.response_wrapper(resp, SnapshotV2)
883+
'/crypto/snapshots',
884+
data={'symbols': symbols},
885+
api_version='v1beta2')
886+
return self.response_wrapper(resp['snapshots'], SnapshotsV2)
950887

951-
def get_latest_crypto_snapshots(self,
952-
symbols: List[str],
953-
exchange: str) -> SnapshotsV2:
888+
def get_crypto_snapshots(self, symbols: List[str]) -> SnapshotsV2:
954889
resp = self.data_get(
955890
'/crypto/snapshots',
956-
data={'exchange': exchange, 'symbols': _join_with_commas(symbols)},
957-
api_version='v1beta1')
891+
data={'symbols': _join_with_commas(symbols)},
892+
api_version='v1beta2')
958893
return self.response_wrapper(resp['snapshots'], SnapshotsV2)
959894

895+
def get_latest_crypto_orderbook(self, symbol: str) -> OrderbookV2:
896+
resp = self.data_get(
897+
'/crypto/latest/orderbooks',
898+
data={'symbols': symbol},
899+
api_version='v1beta2')
900+
return self.response_wrapper(resp['orderbooks'], OrderbooksV2)
901+
902+
def get_latest_crypto_orderbooks(self, symbols: List[str]) -> OrderbookV2:
903+
resp = self.data_get(
904+
'/crypto/latest/orderbooks',
905+
data={'symbols': _join_with_commas(symbols)},
906+
api_version='v1beta2')
907+
return self.response_wrapper(resp['orderbooks'], OrderbooksV2)
908+
960909
def get_news_iter(self,
961910
symbol: Optional[Union[str, List[str]]] = None,
962911
start: Optional[str] = None,

alpaca_trade_api/stream.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ def __init__(self,
464464
self._key_id = key_id
465465
self._secret_key = secret_key
466466
base_url = re.sub(r'^http', 'ws', base_url)
467-
endpoint = base_url + '/v1beta1/crypto'
467+
endpoint = base_url + '/v1beta2/crypto'
468468
if exchanges:
469469
if isinstance(exchanges, str):
470470
endpoint += '?exchanges=' + exchanges

0 commit comments

Comments
 (0)