Skip to content

Commit f54b5a5

Browse files
authored
Add sort parameter and re-add historical crypto quotes (#718)
* Add sort parameter and re-add historical crypto quotes * remove python 3.7 from circleci because it has reached EOL
1 parent 8eecc4b commit f54b5a5

File tree

2 files changed

+62
-17
lines changed

2 files changed

+62
-17
lines changed

.circleci/config.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
steps:
4343
- run: echo "hello python 3.6.4"
4444
- checkout
45-
45+
4646
# Download and cache dependencies
4747
- restore_cache:
4848
keys:
@@ -162,9 +162,6 @@ workflows:
162162
version: 2
163163
build:
164164
jobs:
165-
# - build-python27
166-
# - build-test-python36
167-
- build-test-python37
168165
- build-python38
169166
- build-python39
170167
- build-test-python310

alpaca_trade_api/rest.py

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,8 @@ def _data_get(self,
563563
page_token = None
564564
total_items = 0
565565
limit = kwargs.get('limit')
566-
is_multi_symbol = not isinstance(symbol_or_symbols, str)
566+
is_multi_symbol = api_version == 'v1beta3' or \
567+
not isinstance(symbol_or_symbols, str)
567568
if resp_grouped_by_symbol is None:
568569
resp_grouped_by_symbol = is_multi_symbol
569570
while True:
@@ -578,7 +579,7 @@ def _data_get(self,
578579
path = f'/{endpoint_base}'
579580
if loc:
580581
path += f'/{loc}'
581-
if api_version == 'v1beta3' or is_multi_symbol:
582+
if is_multi_symbol:
582583
data['symbols'] = _join_with_commas(symbol_or_symbols)
583584
elif symbol_or_symbols:
584585
path += f'/{symbol_or_symbols}'
@@ -611,13 +612,15 @@ def get_trades_iter(self,
611612
limit: int = None,
612613
feed: Optional[str] = None,
613614
asof: Optional[str] = None,
615+
sort: Optional[Sort] = None,
614616
raw=False) -> TradeIterator:
615617
trades = self._data_get('trades', symbol,
616618
start=start,
617619
end=end,
618620
limit=limit,
619621
feed=feed,
620622
asof=asof,
623+
sort=sort,
621624
)
622625
for trade in trades:
623626
if raw:
@@ -632,13 +635,15 @@ def get_trades(self,
632635
limit: int = None,
633636
feed: Optional[str] = None,
634637
asof: Optional[str] = None,
638+
sort: Optional[Sort] = None,
635639
) -> TradesV2:
636640
trades = list(self.get_trades_iter(symbol,
637641
start=start,
638642
end=end,
639643
limit=limit,
640644
feed=feed,
641645
asof=asof,
646+
sort=sort,
642647
raw=True))
643648
return TradesV2(trades)
644649

@@ -649,13 +654,15 @@ def get_quotes_iter(self,
649654
limit: int = None,
650655
feed: Optional[str] = None,
651656
asof: Optional[str] = None,
657+
sort: Optional[Sort] = None,
652658
raw=False) -> QuoteIterator:
653659
quotes = self._data_get('quotes', symbol,
654660
start=start,
655661
end=end,
656662
limit=limit,
657663
feed=feed,
658664
asof=asof,
665+
sort=sort,
659666
)
660667
for quote in quotes:
661668
if raw:
@@ -670,6 +677,7 @@ def get_quotes(self,
670677
limit: int = None,
671678
feed: Optional[str] = None,
672679
asof: Optional[str] = None,
680+
sort: Optional[Sort] = None,
673681
) -> QuotesV2:
674682
quotes = list(self.get_quotes_iter(symbol=symbol,
675683
start=start,
@@ -678,6 +686,7 @@ def get_quotes(self,
678686
feed=feed,
679687
raw=True,
680688
asof=asof,
689+
sort=sort,
681690
))
682691
return QuotesV2(quotes)
683692

@@ -690,6 +699,7 @@ def get_bars_iter(self,
690699
limit: int = None,
691700
feed: Optional[str] = None,
692701
asof: Optional[str] = None,
702+
sort: Optional[Sort] = None,
693703
raw=False) -> BarIterator:
694704
bars = self._data_get('bars', symbol,
695705
timeframe=timeframe,
@@ -698,7 +708,9 @@ def get_bars_iter(self,
698708
end=end,
699709
limit=limit,
700710
feed=feed,
701-
asof=asof)
711+
asof=asof,
712+
sort=sort,
713+
)
702714
for bar in bars:
703715
if raw:
704716
yield bar
@@ -714,6 +726,7 @@ def get_bars(self,
714726
limit: int = None,
715727
feed: Optional[str] = None,
716728
asof: Optional[str] = None,
729+
sort: Optional[Sort] = None,
717730
) -> BarsV2:
718731
bars = list(self.get_bars_iter(symbol,
719732
timeframe,
@@ -723,6 +736,7 @@ def get_bars(self,
723736
limit,
724737
feed=feed,
725738
asof=asof,
739+
sort=sort,
726740
raw=True))
727741
return BarsV2(bars)
728742

@@ -789,42 +803,75 @@ def get_snapshots(self, symbols: List[str],
789803
return self.response_wrapper(resp, SnapshotsV2)
790804

791805
def get_crypto_trades_iter(self,
792-
symbol: str,
806+
symbol: Union[str, List[str]],
793807
start: Optional[str] = None,
794808
end: Optional[str] = None,
795809
limit: int = None,
810+
sort: Optional[Sort] = None,
796811
loc: str = "us",
797812
raw=False) -> TradeIterator:
798813
trades = self._data_get('trades', symbol,
799814
api_version='v1beta3', endpoint_base='crypto',
800-
start=start, end=end, limit=limit, loc=loc)
815+
start=start, end=end, limit=limit, sort=sort,
816+
loc=loc)
801817
for trade in trades:
802818
if raw:
803819
yield trade
804820
else:
805821
yield self.response_wrapper(trade, Trade)
806822

807823
def get_crypto_trades(self,
808-
symbol: str,
824+
symbol: Union[str, List[str]],
809825
start: Optional[str] = None,
810826
end: Optional[str] = None,
811827
limit: int = None,
828+
sort: Optional[Sort] = None,
812829
loc: str = "us") -> TradesV2:
813830
return TradesV2(list(self.get_crypto_trades_iter(
814-
symbol, start, end, limit, loc, raw=True)))
831+
symbol, start, end, limit, sort, loc, raw=True)))
832+
833+
def get_crypto_quotes_iter(self,
834+
symbol: Union[str, List[str]],
835+
start: Optional[str] = None,
836+
end: Optional[str] = None,
837+
limit: int = None,
838+
sort: Optional[Sort] = None,
839+
loc: str = "us",
840+
raw=False) -> QuoteIterator:
841+
quotes = self._data_get('quotes', symbol,
842+
api_version='v1beta3', endpoint_base='crypto',
843+
start=start, end=end, limit=limit, sort=sort,
844+
loc=loc)
845+
for quote in quotes:
846+
if raw:
847+
yield quote
848+
else:
849+
yield self.response_wrapper(quote, Quote)
850+
851+
def get_crypto_quotes(self,
852+
symbol: Union[str, List[str]],
853+
start: Optional[str] = None,
854+
end: Optional[str] = None,
855+
limit: int = None,
856+
sort: Optional[Sort] = None,
857+
loc: str = "us") -> QuotesV2:
858+
return QuotesV2(list(self.get_crypto_quotes_iter(
859+
symbol, start, end, limit, sort, loc, raw=True)))
815860

816861
def get_crypto_bars_iter(self,
817862
symbol: Union[str, List[str]],
818863
timeframe: TimeFrame,
819864
start: Optional[str] = None,
820865
end: Optional[str] = None,
821866
limit: int = None,
867+
sort: Optional[Sort] = None,
822868
loc: str = "us",
823869
raw=False) -> BarIterator:
824870
bars = self._data_get('bars', symbol,
825871
api_version='v1beta3', endpoint_base='crypto',
826872
timeframe=timeframe,
827-
start=start, end=end, limit=limit, loc=loc)
873+
start=start, end=end, limit=limit, sort=sort,
874+
loc=loc)
828875
for bar in bars:
829876
if raw:
830877
yield bar
@@ -837,9 +884,10 @@ def get_crypto_bars(self,
837884
start: Optional[str] = None,
838885
end: Optional[str] = None,
839886
limit: int = None,
887+
sort: Optional[Sort] = None,
840888
loc: str = "us") -> BarsV2:
841889
return BarsV2(list(self.get_crypto_bars_iter(
842-
symbol, timeframe, start, end, limit, loc, raw=True)))
890+
symbol, timeframe, start, end, limit, sort, loc, raw=True)))
843891

844892
def get_latest_crypto_bars(self, symbols: List[str],
845893
loc: str = "us") -> LatestBarsV2:
@@ -1124,7 +1172,7 @@ def response_wrapper(self, obj, entity: Entity):
11241172
return entity(obj)
11251173

11261174

1127-
def _join_with_commas(lst: List[str]) -> str:
1128-
if isinstance(lst, str):
1129-
raise ValueError('expected list, str found')
1130-
return ','.join(lst)
1175+
def _join_with_commas(x: Union[str, List[str]]) -> str:
1176+
if isinstance(x, str):
1177+
return x
1178+
return ','.join(x)

0 commit comments

Comments
 (0)