@@ -328,6 +328,8 @@ async def get_bars(
328328 unit : int = 2 ,
329329 limit : int | None = None ,
330330 partial : bool = True ,
331+ start_time : datetime .datetime | None = None ,
332+ end_time : datetime .datetime | None = None ,
331333 ) -> pl .DataFrame :
332334 """
333335 Retrieve historical OHLCV bar data for an instrument.
@@ -338,12 +340,14 @@ async def get_bars(
338340
339341 Args:
340342 symbol: Symbol of the instrument (e.g., "MGC", "MNQ", "ES")
341- days: Number of days of historical data (default: 8)
343+ days: Number of days of historical data (default: 8, ignored if start_time/end_time provided )
342344 interval: Interval between bars in the specified unit (default: 5)
343345 unit: Time unit for the interval (default: 2 for minutes)
344346 1=Second, 2=Minute, 3=Hour, 4=Day, 5=Week, 6=Month
345347 limit: Maximum number of bars to retrieve (auto-calculated if None)
346348 partial: Include incomplete/partial bars (default: True)
349+ start_time: Optional start datetime (overrides days if provided)
350+ end_time: Optional end datetime (defaults to now if not provided)
347351
348352 Returns:
349353 pl.DataFrame: DataFrame with OHLCV data and timezone-aware timestamps
@@ -371,6 +375,11 @@ async def get_bars(
371375 >>> # V3: Different time units available
372376 >>> # unit=1 (seconds), 2 (minutes), 3 (hours), 4 (days)
373377 >>> hourly_data = await client.get_bars("ES", days=1, interval=1, unit=3)
378+ >>> # V3: Use specific time range
379+ >>> from datetime import datetime
380+ >>> start = datetime(2025, 1, 1, 9, 30)
381+ >>> end = datetime(2025, 1, 1, 16, 0)
382+ >>> data = await client.get_bars("ES", start_time=start, end_time=end)
374383 """
375384 with LogContext (
376385 logger ,
@@ -383,27 +392,55 @@ async def get_bars(
383392 ):
384393 await self ._ensure_authenticated ()
385394
395+ # Calculate date range
396+ from datetime import timedelta
397+
398+ if start_time is not None or end_time is not None :
399+ # Use provided time range
400+ if start_time is not None :
401+ # Ensure timezone awareness
402+ if start_time .tzinfo is None :
403+ start_date = pytz .UTC .localize (start_time )
404+ else :
405+ start_date = start_time .astimezone (pytz .UTC )
406+ else :
407+ # Default to days parameter ago if only end_time provided
408+ start_date = datetime .datetime .now (pytz .UTC ) - timedelta (days = days )
409+
410+ if end_time is not None :
411+ # Ensure timezone awareness
412+ if end_time .tzinfo is None :
413+ end_date = pytz .UTC .localize (end_time )
414+ else :
415+ end_date = end_time .astimezone (pytz .UTC )
416+ else :
417+ # Default to now if only start_time provided
418+ end_date = datetime .datetime .now (pytz .UTC )
419+
420+ # Calculate days for cache key (approximate)
421+ days_calc = int ((end_date - start_date ).total_seconds () / 86400 )
422+ cache_key = f"{ symbol } _{ start_date .isoformat ()} _{ end_date .isoformat ()} _{ interval } _{ unit } _{ partial } "
423+ else :
424+ # Use days parameter
425+ start_date = datetime .datetime .now (pytz .UTC ) - timedelta (days = days )
426+ end_date = datetime .datetime .now (pytz .UTC )
427+ days_calc = days
428+ cache_key = f"{ symbol } _{ days } _{ interval } _{ unit } _{ partial } "
429+
386430 # Check market data cache
387- cache_key = f"{ symbol } _{ days } _{ interval } _{ unit } _{ partial } "
388431 cached_data = self .get_cached_market_data (cache_key )
389432 if cached_data is not None :
390433 logger .debug (LogMessages .CACHE_HIT , extra = {"cache_key" : cache_key })
391434 return cached_data
392435
393436 logger .debug (
394437 LogMessages .DATA_FETCH ,
395- extra = {"symbol" : symbol , "days" : days , "interval" : interval },
438+ extra = {"symbol" : symbol , "days" : days_calc , "interval" : interval },
396439 )
397440
398441 # Lookup instrument
399442 instrument = await self .get_instrument (symbol )
400443
401- # Calculate date range
402- from datetime import timedelta
403-
404- start_date = datetime .datetime .now (pytz .UTC ) - timedelta (days = days )
405- end_date = datetime .datetime .now (pytz .UTC )
406-
407444 # Calculate limit based on unit type
408445 if limit is None :
409446 if unit == 1 : # Seconds
0 commit comments