@@ -413,6 +413,106 @@ def _parse_date_for_filtering(date_input):
413413 print (f"Error: { str (e )} " )
414414 return pd .DataFrame ()
415415
416+ def get_equity_daily (ticker , start_date = None , end_date = None , provider = "FirstRateData" ):
417+ """
418+ Fetch Equity daily data from gRPC API for a given ticker and optionally filter by date range.
419+
420+ Parameters:
421+ ticker (str): The ticker symbol
422+ start_date (datetime.date or str, optional): Start date for data retrieval (format: '2025-05-28').
423+ If None, no start limit is applied
424+ end_date (datetime.date or str, optional): End date for data retrieval (format: '2025-05-28').
425+ If None, no end limit is applied
426+ provider (str): Data provider, default is "FirstRateData"
427+
428+ # Example usage:
429+ # df = get_equity_daily('AAPL US Equity') # Get all available data
430+ # df = get_equity_daily('AAPL US Equity', start_date='2024-01-01') # From Jan 1, 2024 onwards
431+ # df = get_equity_daily('AAPL US Equity', end_date='2024-12-31') # Up to Dec 31, 2024
432+ # df = get_equity_daily('AAPL US Equity', start_date='2024-01-01', end_date='2024-12-31') # Full year 2024
433+
434+ Returns:
435+ pd.DataFrame: DataFrame with Date as index and all available fields as columns
436+ """
437+
438+ def _parse_date_for_filtering (date_input ):
439+ """Parse date input for DataFrame filtering (returns date object, not Google date)"""
440+ if date_input is None :
441+ return None
442+ if isinstance (date_input , date ):
443+ return date_input
444+ if isinstance (date_input , datetime ):
445+ return date_input .date ()
446+ if isinstance (date_input , str ):
447+ return datetime .strptime (date_input , '%Y-%m-%d' ).date ()
448+ raise ValueError (f"Invalid date type: { type (date_input )} " )
449+
450+ id = identifier .Identifier (
451+ ticker = ticker ,
452+ asset_type = asset .AssetType .ASSET_TYPE_EQUITY
453+ )
454+ id .provider .value = provider
455+
456+ request = daily_bars .DailyBarsRequest (identifier = id )
457+
458+ try :
459+ # Open gRPC channel
460+ with channel_helpers .get_grpc_channel () as channel :
461+ # Send request and receive response
462+ token = token_helpers .get_token ()
463+
464+ # Create service stub
465+ service = daily_bars_service .DailyBarsServiceStub (channel )
466+ response = service .DailyBars (request = request , metadata = [('authorization' , token )])
467+
468+ # Process the response
469+ if not response or not response .data :
470+ print ("No data received" )
471+ return pd .DataFrame ()
472+
473+ dates = [datetime (b .date .year , b .date .month , b .date .day ) for b in response .data ]
474+ opens = [b .open for b in response .data ]
475+ highs = [b .high for b in response .data ]
476+ lows = [b .low for b in response .data ]
477+ closes = [b .close for b in response .data ]
478+ volumes = [b .volume for b in response .data ]
479+
480+ data_dict = {'Date' : dates , 'Open' : opens , 'High' : highs , 'Low' : lows , 'Close' : closes , 'Volume' : volumes }
481+ df = pd .DataFrame (data = data_dict )
482+ df = df .set_index ('Date' )
483+
484+ # Sort by date for better readability
485+ df = df .sort_index ()
486+
487+ # Apply date filtering if specified
488+ if start_date is not None or end_date is not None :
489+ # Parse date inputs
490+ if start_date is not None :
491+ start_date_parsed = _parse_date_for_filtering (start_date )
492+ start_datetime = datetime .combine (start_date_parsed , datetime .min .time ())
493+
494+ if end_date is not None :
495+ end_date_parsed = _parse_date_for_filtering (end_date )
496+ end_datetime = datetime .combine (end_date_parsed , datetime .max .time ())
497+
498+ # Filter the DataFrame
499+ if start_date is not None and end_date is not None :
500+ df = df [(df .index >= start_datetime ) & (df .index <= end_datetime )]
501+ elif start_date is not None :
502+ df = df [df .index >= start_datetime ]
503+ elif end_date is not None :
504+ df = df [df .index <= end_datetime ]
505+
506+ return df
507+
508+ except grpc .RpcError as e :
509+ print (f"gRPC Error: { e .code ().name } " )
510+ print (f"Details: { e .details ()} " )
511+ return pd .DataFrame ()
512+ except Exception as e :
513+ print (f"Error: { str (e )} " )
514+ return pd .DataFrame ()
515+
416516def _python_date_to_google_date (py_date ):
417517 """Convert Python date to Google Date protobuf message"""
418518 return date_pb2 .Date (year = py_date .year , month = py_date .month , day = py_date .day )
0 commit comments