44from datetime import datetime
55from typing import Literal , List
66
7- from finwar_data_ingestion .resources import PostgreSQLResource , PolygonResource
7+ from finwar_data_ingestion .resources import PostgreSQLResource , MassiveResource
88
99
10- MAX_POLYGON_REQ_RETRY = 3
10+ MAX_MASSIVE_REQ_RETRY = 3
1111
1212
1313class StocksIntradayHistoryComponent (dg .Component , dg .Model , dg .Resolvable ):
1414 """Represents historical stock quotation for one or more ticker symbols.
1515
16- The data is retrieved from the [Polygon.io ](https://polygon.io ) API and returned as a
16+ The data is retrieved from the [Massive ](https://massive.com ) API and returned as a
1717 :class:`pandas.DataFrame`. The data also contains the trading volume.
1818 It is then loaded as a TimescaleDB table.
1919
@@ -25,7 +25,7 @@ class StocksIntradayHistoryComponent(dg.Component, dg.Model, dg.Resolvable):
2525 time_partitioning (Literal["daily", "weekly", "monthly"]): The partitioning frequency
2626 for the data retrieval. The partitioning unit should be shorter or equal to the
2727 requested time window. Default is ``"monthly"``.
28- polygon_api_key (str): API key for authenticating with the Polygon.io API.
28+ massive_api_key (str): API key for authenticating with the Massive API.
2929 precision (Literal["second", "minute", "day", "week", "month", "quarter", "year"]):
3030 The granularity of the bars. Must be finer than or equal to the requested
3131 time window. Default is ``"day"``.
@@ -42,7 +42,7 @@ class StocksIntradayHistoryComponent(dg.Component, dg.Model, dg.Resolvable):
4242 start_date : str
4343 end_date : str | None = None
4444 time_partitioning : Literal ['daily' , 'weekly' , 'monthly' ] = 'monthly'
45- polygon_api_key : str
45+ massive_api_key : str
4646 precision : Literal ['second' , 'minute' , 'day' , 'week' , 'month' , 'quarter' , 'year' ] = 'day'
4747 adjusted : bool = False
4848 table_name : str = 'stocks_history'
@@ -57,7 +57,7 @@ def get_spec(cls) -> dg.ComponentTypeSpec:
5757 return dg .ComponentTypeSpec (
5858 description = cls .__doc__ ,
5959 owners = ['contact@kelps.org' , 'guilhem.sante@kelps.org' ],
60- tags = ['stocks' , 'intraday' , 'polygon.io ' , 'timescaledb' ],
60+ tags = ['stocks' , 'intraday' , 'massive.com ' , 'timescaledb' ],
6161 )
6262
6363 def build_defs (self , context : dg .ComponentLoadContext ) -> dg .Definitions :
@@ -84,57 +84,57 @@ def build_defs(self, context: dg.ComponentLoadContext) -> dg.Definitions:
8484 group_name = 'ingestion' ,
8585 code_version = '0.3.0' ,
8686 description = """
87- Extract the stocks intraday value from the Polygon API.
87+ Extract the stocks intraday value from the Massive API.
8888 """ ,
8989 partitions_def = partitions_matrix ,
9090 )
9191 def download_stocks_intraday_history (
9292 context : AssetExecutionContext ,
93- polygon : PolygonResource ,
93+ massive : MassiveResource ,
9494 ) -> dg .MaterializeResult :
9595 partition_keys = context .partition_key .keys_by_dimension
9696 time_window = time_partitioning .time_window_for_partition_key (partition_keys ['time' ])
9797 symbol = partition_keys ['symbol' ]
9898
99- with polygon .get_client () as client :
100- for attempt in range (0 , MAX_POLYGON_REQ_RETRY ):
101- try :
102- res = client .get_aggregate_bars (
103- symbol = symbol ,
104- multiplier = 1 ,
105- adjusted = self .adjusted ,
106- timespan = self .precision ,
107- from_date = time_window .start ,
108- to_date = time_window .end ,
109- limit = 50000 , # API max limit
99+ client = massive .get_client ()
100+
101+ for attempt in range (0 , MAX_MASSIVE_REQ_RETRY ):
102+ try :
103+ aggs = []
104+ for a in client .list_aggs (
105+ ticker = symbol ,
106+ multiplier = 1 ,
107+ adjusted = self .adjusted ,
108+ timespan = self .precision ,
109+ from_ = time_window .start ,
110+ to = time_window .end ,
111+ limit = 50000 , # API max limit
112+ ):
113+ aggs .append (a )
114+
115+ except Exception as e :
116+ if attempt == MAX_MASSIVE_REQ_RETRY :
117+ raise dg .Failure (
118+ description = f'failed to get intraday stock data from Massive API: { e } '
119+ )
120+ else :
121+ context .log .warning (
122+ f'Massive API request failed (attempt n°{ attempt + 1 } /{ MAX_MASSIVE_REQ_RETRY } ): { e } ' ,
110123 )
111-
112- if res ['status' ] == 'ERROR' or res ['results' ] is None :
113- raise Exception (res ['error' ])
114- break
115- except Exception as e :
116- if attempt == MAX_POLYGON_REQ_RETRY :
117- raise dg .Failure (
118- description = f'failed to get intraday stock data from Polygon API: { e } '
119- )
120- else :
121- context .log .warning (
122- f'polygon.io API request failed (attempt n°{ attempt + 1 } /{ MAX_POLYGON_REQ_RETRY } ): { e } ' ,
123- )
124124
125125 return dg .MaterializeResult (
126126 value = pd .DataFrame (
127127 [
128128 {
129- 'timestamp' : datetime .fromtimestamp (bar [ 't' ] / 1000 ),
129+ 'timestamp' : datetime .fromtimestamp (bar . timestamp / 1000 ),
130130 'symbol' : symbol ,
131- 'open' : bar [ 'o' ] ,
132- 'high' : bar [ 'h' ] ,
133- 'low' : bar [ 'l' ] ,
134- 'close' : bar [ 'c' ] ,
135- 'volume' : bar [ 'v' ] ,
131+ 'open' : bar . open ,
132+ 'high' : bar . high ,
133+ 'low' : bar . low ,
134+ 'close' : bar . close ,
135+ 'volume' : bar . volume ,
136136 }
137- for bar in res [ 'results' ]
137+ for bar in aggs
138138 ]
139139 ),
140140 metadata = {
@@ -222,8 +222,8 @@ def load_stocks_intraday_history(
222222 load_stocks_intraday_history ,
223223 ],
224224 resources = {
225- 'polygon ' : PolygonResource (
226- api_key = self .polygon_api_key ,
225+ 'massive ' : MassiveResource (
226+ api_key = self .massive_api_key ,
227227 ),
228228 'postgresql' : PostgreSQLResource (
229229 username = self .timescaledb_username ,
0 commit comments