Skip to content

Commit

Permalink
Add crypto marketdata
Browse files Browse the repository at this point in the history
  • Loading branch information
gnvk committed Sep 13, 2021
1 parent 2538518 commit a671fb4
Show file tree
Hide file tree
Showing 4 changed files with 464 additions and 45 deletions.
9 changes: 6 additions & 3 deletions alpaca_trade_api/entity_v2.py
Expand Up @@ -11,24 +11,27 @@
"p": "price",
"s": "size",
"t": "timestamp",
"z": "tape"
"z": "tape", # stocks only
"tks": "takerside" # crypto only
}

quote_mapping_v2 = {
"S": "symbol",
"x": "exchange", # crypto only
"ax": "ask_exchange",
"ap": "ask_price",
"as": "ask_size",
"bx": "bid_exchange",
"bp": "bid_price",
"bs": "bid_size",
"c": "conditions",
"c": "conditions", # stocks only
"t": "timestamp",
"z": "tape"
"z": "tape" # stocks only
}

bar_mapping_v2 = {
"S": "symbol",
"x": "exchange", # crypto only
"o": "open",
"h": "high",
"l": "low",
Expand Down
154 changes: 135 additions & 19 deletions alpaca_trade_api/rest.py
@@ -1,10 +1,9 @@
import logging
import os
from typing import Iterator, List, Union
from typing import Iterator, List, Optional, Union
import requests
from requests.exceptions import HTTPError
import time
from enum import Enum
from .common import (
get_base_url,
get_data_url,
Expand Down Expand Up @@ -70,7 +69,7 @@ def response(self):
return self._http_error.response


class TimeFrame(Enum):
class TimeFrame(str):
Day = "1Day"
Hour = "1Hour"
Minute = "1Min"
Expand Down Expand Up @@ -545,7 +544,12 @@ def get_last_quote(self, symbol: str) -> Quote:
resp = self.data_get('/last_quote/stocks/{}'.format(symbol))
return self.response_wrapper(resp['last'], Quote)

def _data_get_v2(self, endpoint: str, symbol: str, **kwargs):
def _data_get(self,
endpoint: str,
symbol: str,
api_version: str = 'v2',
endpoint_base: str = 'stocks',
**kwargs):
page_token = None
total_items = 0
limit = kwargs.get('limit')
Expand All @@ -558,9 +562,10 @@ def _data_get_v2(self, endpoint: str, symbol: str, **kwargs):
data = kwargs
data['limit'] = actual_limit
data['page_token'] = page_token
resp = self.data_get('/stocks/{}/{}'.format(symbol, endpoint),
data=data, api_version='v2')
items = resp.get(endpoint, [])
resp = self.data_get(
'/{}/{}/{}'.format(endpoint_base, symbol, endpoint),
data=data, api_version=api_version)
items = resp.get(endpoint, []) or []
for item in items:
yield item
total_items += len(items)
Expand All @@ -574,8 +579,8 @@ def get_trades_iter(self,
end: str,
limit: int = None,
raw=False) -> TradeIterator:
trades = self._data_get_v2('trades', symbol,
start=start, end=end, limit=limit)
trades = self._data_get('trades', symbol,
start=start, end=end, limit=limit)
for trade in trades:
if raw:
yield trade
Expand All @@ -601,8 +606,8 @@ def get_quotes_iter(self,
end: str,
limit: int = None,
raw=False) -> QuoteIterator:
quotes = self._data_get_v2('quotes', symbol,
start=start, end=end, limit=limit)
quotes = self._data_get('quotes', symbol,
start=start, end=end, limit=limit)
for quote in quotes:
if raw:
yield quote
Expand Down Expand Up @@ -630,10 +635,10 @@ def get_bars_iter(self,
adjustment: str = 'raw',
limit: int = None,
raw=False) -> BarIterator:
bars = self._data_get_v2('bars', symbol,
timeframe=timeframe.value,
adjustment=adjustment,
start=start, end=end, limit=limit)
bars = self._data_get('bars', symbol,
timeframe=timeframe,
adjustment=adjustment,
start=start, end=end, limit=limit)
for bar in bars:
if raw:
yield bar
Expand Down Expand Up @@ -662,15 +667,15 @@ def get_latest_trade(self, symbol: str) -> TradeV2:
Get the latest trade for the given symbol
"""
resp = self.data_get(
'/stocks/{}/trades/latest'.format(symbol),
api_version='v2')
'/stocks/{}/trades/latest'.format(symbol),
api_version='v2')
return self.response_wrapper(resp['trade'], TradeV2)

def get_latest_quote(self, symbol: str) -> QuoteV2:
"""Get the latest quote for the given symbol"""
resp = self.data_get(
'/stocks/{}/quotes/latest'.format(symbol),
api_version='v2')
'/stocks/{}/quotes/latest'.format(symbol),
api_version='v2')
return self.response_wrapper(resp['quote'], QuoteV2)

def get_snapshot(self, symbol: str) -> SnapshotV2:
Expand All @@ -686,6 +691,117 @@ def get_snapshots(self, symbols: List[str]) -> SnapshotsV2:
api_version='v2')
return self.response_wrapper(resp, SnapshotsV2)

def get_crypto_trades_iter(self,
symbol: str,
start: Optional[str] = None,
end: Optional[str] = None,
limit: int = None,
exchanges: Optional[List[str]] = None,
raw=False) -> TradeIterator:
trades = self._data_get('trades', symbol,
api_version='v1beta1', endpoint_base='crypto',
start=start, end=end, limit=limit,
exchanges=exchanges)
for trade in trades:
if raw:
yield trade
else:
yield self.response_wrapper(trade, Trade)

def get_crypto_trades(self,
symbol: str,
start: Optional[str] = None,
end: Optional[str] = None,
limit: int = None,
exchanges: Optional[List[str]] = None,
) -> TradesV2:
return TradesV2(list(self.get_crypto_trades_iter(
symbol, start, end, limit, exchanges, raw=True)))

def get_crypto_quotes_iter(self,
symbol: str,
start: Optional[str] = None,
end: Optional[str] = None,
limit: int = None,
exchanges: Optional[List[str]] = None,
raw=False) -> QuoteIterator:
quotes = self._data_get('quotes', symbol,
api_version='v1beta1', endpoint_base='crypto',
start=start, end=end, limit=limit,
exchanges=exchanges)
for quote in quotes:
if raw:
yield quote
else:
yield self.response_wrapper(quote, Quote)

def get_crypto_quotes(self,
symbol: str,
start: Optional[str] = None,
end: Optional[str] = None,
limit: int = None,
exchanges: Optional[List[str]] = None,
) -> QuotesV2:
return QuotesV2(list(self.get_crypto_quotes_iter(
symbol, start, end, limit, exchanges, raw=True)))

def get_crypto_bars_iter(self,
symbol: str,
timeframe: TimeFrame,
start: Optional[str] = None,
end: Optional[str] = None,
limit: int = None,
exchanges: Optional[List[str]] = None,
raw=False) -> BarIterator:
bars = self._data_get('bars', symbol,
api_version='v1beta1', endpoint_base='crypto',
timeframe=timeframe,
start=start, end=end, limit=limit,
exchanges=exchanges)
for bar in bars:
if raw:
yield bar
else:
yield self.response_wrapper(bar, Bar)

def get_crypto_bars(self,
symbol: str,
timeframe: TimeFrame,
start: Optional[str] = None,
end: Optional[str] = None,
limit: int = None,
exchanges: Optional[List[str]] = None,
) -> BarsV2:
return BarsV2(list(self.get_crypto_bars_iter(
symbol, timeframe, start, end, limit, exchanges, raw=True)))

def get_latest_crypto_trade(self, symbol: str, exchange: str) -> TradeV2:
resp = self.data_get(
'/crypto/{}/trades/latest'.format(symbol),
data={'exchange': exchange},
api_version='v1beta1')
return self.response_wrapper(resp['trade'], TradeV2)

def get_latest_crypto_quote(self, symbol: str, exchange: str) -> QuoteV2:
resp = self.data_get(
'/crypto/{}/quotes/latest'.format(symbol),
data={'exchange': exchange},
api_version='v1beta1')
return self.response_wrapper(resp['quote'], QuoteV2)

def get_latest_crypto_xbbo(self,
symbol: str,
exchanges: Optional[List[str]] = None,
) -> QuoteV2:
params = {}
if exchanges:
params['exchanges'] = ','.join(exchanges)
resp = self.data_get(
'/crypto/{}/xbbo/latest'.format(symbol),
data=params,
api_version='v1beta1')
return self.response_wrapper(resp['xbbo'], QuoteV2)

def get_clock(self) -> Clock:
resp = self.get('/clock')
return self.response_wrapper(resp, Clock)
Expand Down

0 comments on commit a671fb4

Please sign in to comment.