44import dateutil .parser
55import requests
66from .entity import (
7- Aggsv2 , Aggsv2Set , Trade , TradesV2 , Quote , QuotesV2 ,
7+ Entity , Aggsv2 , Aggsv2Set , Trade , TradesV2 , Quote , QuotesV2 ,
88 Exchange , SymbolTypeMap , ConditionMap , Company , Dividends , Splits ,
99 Earnings , Financials , NewsList , Ticker , DailyOpenClose , Symbol
1010)
@@ -92,9 +92,18 @@ def fix_daily_bar_date(date, timespan):
9292
9393class REST (object ):
9494
95- def __init__ (self , api_key : str , staging : bool = False ):
95+ def __init__ (self , api_key : str ,
96+ staging : bool = False ,
97+ raw_data : bool = False
98+ ):
99+ """
100+ :param staging: do we work with the staging server
101+ :param raw_data: should we return api response raw or wrap it with
102+ Entity objects.
103+ """
96104 self ._api_key : str = get_polygon_credentials (api_key )
97105 self ._staging : bool = staging
106+ self ._use_raw_data : bool = raw_data
98107 self ._session = requests .Session ()
99108
100109 def _request (self , method : str , path : str , params : dict = None ,
@@ -120,11 +129,15 @@ def get(self, path: str, params: dict = None, version: str = 'v1'):
120129
121130 def exchanges (self ) -> Exchanges :
122131 path = '/meta/exchanges'
123- return [Exchange (o ) for o in self .get (path )]
132+ resp = self .get (path )
133+ if self ._use_raw_data :
134+ return resp
135+ else :
136+ return [self .response_wrapper (o , Exchange ) for o in resp ]
124137
125138 def symbol_type_map (self ) -> SymbolTypeMap :
126139 path = '/meta/symbol-types'
127- return SymbolTypeMap (self .get (path ))
140+ return self . response_wrapper (self .get (path ), SymbolTypeMap )
128141
129142 def historic_trades_v2 (self ,
130143 symbol : str ,
@@ -154,9 +167,8 @@ def historic_trades_v2(self,
154167 params ['reverse' ] = reverse
155168 if limit is not None :
156169 params ['limit' ] = limit
157- raw = self .get (path , params , 'v2' )
158-
159- return TradesV2 (raw )
170+ resp = self .get (path , params , 'v2' )
171+ return self .response_wrapper (resp , TradesV2 )
160172
161173 def historic_quotes_v2 (self ,
162174 symbol : str ,
@@ -186,9 +198,8 @@ def historic_quotes_v2(self,
186198 params ['reverse' ] = reverse
187199 if limit is not None :
188200 params ['limit' ] = limit
189- raw = self .get (path , params , 'v2' )
190-
191- return QuotesV2 (raw )
201+ resp = self .get (path , params , 'v2' )
202+ return self .response_wrapper (resp , QuotesV2 )
192203
193204 def historic_agg_v2 (self ,
194205 symbol : str ,
@@ -226,39 +237,39 @@ def historic_agg_v2(self,
226237 params = {'unadjusted' : unadjusted }
227238 if limit :
228239 params ['limit' ] = limit
229- raw = self .get (path , params , version = 'v2' )
230- return Aggsv2 ( raw )
240+ resp = self .get (path , params , version = 'v2' )
241+ return self . response_wrapper ( resp , Aggsv2 )
231242
232243 def grouped_daily (self , date , unadjusted : bool = False ) -> Aggsv2Set :
233244 path = f'/aggs/grouped/locale/us/market/stocks/{ date } '
234245 params = {'unadjusted' : unadjusted }
235- raw = self .get (path , params , version = 'v2' )
236- return Aggsv2Set ( raw )
246+ resp = self .get (path , params , version = 'v2' )
247+ return self . response_wrapper ( resp , Aggsv2Set )
237248
238249 def daily_open_close (self , symbol : str , date ) -> DailyOpenClose :
239250 path = f'/open-close/{ symbol } /{ date } '
240- raw = self .get (path )
241- return DailyOpenClose ( raw )
251+ resp = self .get (path )
252+ return self . response_wrapper ( resp , DailyOpenClose )
242253
243254 def last_trade (self , symbol : str ) -> Trade :
244255 path = '/last/stocks/{}' .format (symbol )
245- raw = self .get (path )
246- return Trade ( raw [ 'last' ] )
256+ resp = self .get (path )[ 'last' ]
257+ return self . response_wrapper ( resp , Trade )
247258
248259 def last_quote (self , symbol : str ) -> Quote :
249260 path = '/last_quote/stocks/{}' .format (symbol )
250- raw = self .get (path )
261+ resp = self .get (path )[ 'last' ]
251262 # TODO status check
252- return Quote ( raw [ 'last' ] )
263+ return self . response_wrapper ( resp , Quote )
253264
254265 def previous_day_bar (self , symbol : str ) -> Aggsv2 :
255266 path = '/aggs/ticker/{}/prev' .format (symbol )
256- raw = self .get (path , version = 'v2' )
257- return Aggsv2 ( raw )
267+ resp = self .get (path , version = 'v2' )
268+ return self . response_wrapper ( resp , Aggsv2 )
258269
259270 def condition_map (self , ticktype = 'trades' ) -> ConditionMap :
260271 path = '/meta/conditions/{}' .format (ticktype )
261- return ConditionMap (self .get (path ))
272+ return self . response_wrapper (self .get (path ), ConditionMap )
262273
263274 def company (self , symbol : str ) -> Company :
264275 return self ._get_symbol (symbol , 'company' , Company )
@@ -275,7 +286,10 @@ def _get_symbol(self, symbol: str, resource: str, entity):
275286 res = self .get (path , params = params )
276287 if isinstance (res , list ):
277288 res = {o ['symbol' ]: o for o in res }
278- retmap = {sym : entity (res [sym ]) for sym in symbols if sym in res }
289+ if self ._use_raw_data :
290+ retmap = res
291+ else :
292+ retmap = {sym : entity (res [sym ]) for sym in symbols if sym in res }
279293 if not multi :
280294 return retmap .get (symbol )
281295 return retmap
@@ -285,7 +299,8 @@ def dividends(self, symbol: str) -> Dividends:
285299
286300 def splits (self , symbol : str ) -> Splits :
287301 path = f'/reference/splits/{ symbol } '
288- return Splits (self .get (path , version = 'v2' )['results' ])
302+ resp = self .get (path , version = 'v2' )['results' ]
303+ return self .response_wrapper (resp , Splits )
289304
290305 def earnings (self , symbol : str ) -> Earnings :
291306 return self ._get_symbol (symbol , 'earnings' , Earnings )
@@ -303,26 +318,28 @@ def financials_v2(self, symbol: str,
303318 "type" : report_type .name ,
304319 "sort" : sort .value ,
305320 }
306- return Financials ( self .get (path , version = 'v2' ,
307- params = params )[ 'results' ] )
321+ resp = self .get (path , version = 'v2' , params = params )[ 'results' ]
322+ return self . response_wrapper ( resp , Financials )
308323
309324 def news (self , symbol : str ) -> NewsList :
310325 path = '/meta/symbols/{}/news' .format (symbol )
311- return NewsList (self .get (path ))
326+ return self . response_wrapper (self .get (path ), NewsList )
312327
313328 def gainers_losers (self , direction : str = "gainers" ) -> Tickers :
314329 path = '/snapshot/locale/us/markets/stocks/{}' .format (direction )
315- return [
316- Ticker (ticker ) for ticker in
317- self .get (path , version = 'v2' )['tickers' ]
318- ]
330+ resp = self .get (path , version = 'v2' )['tickers' ]
331+ if self ._use_raw_data :
332+ return resp
333+ else :
334+ return [self .response_wrapper (o , Ticker ) for o in resp ]
319335
320336 def all_tickers (self ) -> Tickers :
321337 path = '/snapshot/locale/us/markets/stocks/tickers'
322- return [
323- Ticker (ticker ) for ticker in
324- self .get (path , version = 'v2' )['tickers' ]
325- ]
338+ resp = self .get (path , version = 'v2' )['tickers' ]
339+ if self ._use_raw_data :
340+ return resp
341+ else :
342+ return [self .response_wrapper (o , Ticker ) for o in resp ]
326343
327344 def symbol_list_paginated (self , page : int = 1 ,
328345 per_page : int = 50 ) -> Symbols :
@@ -334,15 +351,34 @@ def symbol_list_paginated(self, page: int = 1,
334351 :return:
335352 """
336353 path = '/reference/tickers'
337- return [Symbol (s ) for s in self .get (path ,
338- version = 'v2' ,
339- params = {
340- "page" : page ,
341- "active" : "true" ,
342- "perpage" : per_page ,
343- "market" : "STOCKS"
344- })['tickers' ]]
354+ resp = self .get (path ,
355+ version = 'v2' ,
356+ params = {
357+ "page" : page ,
358+ "active" : "true" ,
359+ "perpage" : per_page ,
360+ "market" : "STOCKS"
361+ })['tickers' ]
362+ if self ._use_raw_data :
363+ return resp
364+ else :
365+ return [self .response_wrapper (o , Symbol ) for o in resp ]
345366
346367 def snapshot (self , symbol : str ) -> Ticker :
347368 path = '/snapshot/locale/us/markets/stocks/tickers/{}' .format (symbol )
348- return Ticker (self .get (path , version = 'v2' ))
369+ resp = self .get (path , version = 'v2' )
370+ return self .response_wrapper (resp , Ticker )
371+
372+ def response_wrapper (self , obj , entity : Entity ):
373+ """
374+ To allow the user to get raw response from the api, we wrap all
375+ functions with this method, checking if the user has set raw_data
376+ bool. if they didn't, we wrap the response with an Entity object.
377+ :param obj: response from server
378+ :param entity: derivative object of Entity
379+ :return:
380+ """
381+ if self ._use_raw_data :
382+ return obj
383+ else :
384+ return entity (obj )
0 commit comments