@@ -571,3 +571,72 @@ def raise_err(*args, **kwargs):
571571 "Unable to use Arrow filtering, loading entire trades file" in r .message
572572 for r in caplog .records
573573 )
574+
575+
576+ def test_feather_trades_timerange_open_start (feather_dh , trades_full ):
577+ # Open start: stop timestamp but no start (startts=0)
578+ stop_ts = int (trades_full ["timestamp" ].iloc [(2 * len (trades_full )) // 3 ])
579+ tr = TimeRange (None , "date" , startts = 0 , stopts = stop_ts )
580+
581+ filtered = feather_dh .trades_load ("XRP/ETH" , TradingMode .SPOT , timerange = tr )
582+ assert 0 < len (filtered ) < len (trades_full )
583+ assert filtered ["timestamp" ].max () <= stop_ts
584+ # First row should match full's first row
585+ assert filtered .iloc [0 ]["timestamp" ] == trades_full .iloc [0 ]["timestamp" ]
586+
587+
588+ def test_feather_trades_timerange_open_end (feather_dh , trades_full ):
589+ # Open end: start timestamp but no stop (stopts=0)
590+ start_ts = int (trades_full ["timestamp" ].iloc [len (trades_full ) // 3 ])
591+ tr = TimeRange ("date" , None , startts = start_ts , stopts = 0 )
592+
593+ filtered = feather_dh .trades_load ("XRP/ETH" , TradingMode .SPOT , timerange = tr )
594+ assert 0 < len (filtered ) < len (trades_full )
595+ assert filtered ["timestamp" ].min () >= start_ts
596+ # Last row should match full's last row
597+ assert filtered .iloc [- 1 ]["timestamp" ] == trades_full .iloc [- 1 ]["timestamp" ]
598+
599+
600+ def test_feather_trades_timerange_fully_open (feather_dh , trades_full ):
601+ # Fully open: no start or stop bounds (both 0)
602+ tr = TimeRange (None , None , startts = 0 , stopts = 0 )
603+
604+ filtered = feather_dh .trades_load ("XRP/ETH" , TradingMode .SPOT , timerange = tr )
605+ # Should equal unfiltered load
606+ assert_frame_equal (
607+ trades_full .reset_index (drop = True ), filtered .reset_index (drop = True ), check_exact = True
608+ )
609+
610+
611+ def test_feather_build_arrow_time_filter (feather_dh ):
612+ # None timerange should return None
613+ assert feather_dh ._build_arrow_time_filter (None ) is None
614+
615+ # Fully open (both bounds 0) should return None
616+ tr_fully_open = TimeRange (None , None , startts = 0 , stopts = 0 )
617+ assert feather_dh ._build_arrow_time_filter (tr_fully_open ) is None
618+
619+ # Open start (startts=0) should return stop filter only
620+ tr_open_start = TimeRange (None , "date" , startts = 0 , stopts = 1000 )
621+ filter_open_start = feather_dh ._build_arrow_time_filter (tr_open_start )
622+ assert filter_open_start is not None
623+ # Should be a single expression (timestamp <= stopts)
624+ assert str (filter_open_start ).count ("<=" ) == 1
625+ assert str (filter_open_start ).count (">=" ) == 0
626+
627+ # Open end (stopts=0) should return start filter only
628+ tr_open_end = TimeRange ("date" , None , startts = 500 , stopts = 0 )
629+ filter_open_end = feather_dh ._build_arrow_time_filter (tr_open_end )
630+ assert filter_open_end is not None
631+ # Should be a single expression (timestamp >= startts)
632+ assert str (filter_open_end ).count (">=" ) == 1
633+ assert str (filter_open_end ).count ("<=" ) == 0
634+
635+ # Closed range should return combined filter
636+ tr_closed = TimeRange ("date" , "date" , startts = 500 , stopts = 1000 )
637+ filter_closed = feather_dh ._build_arrow_time_filter (tr_closed )
638+ assert filter_closed is not None
639+ # Should contain both >= and <= (combined with &)
640+ filter_str = str (filter_closed )
641+ assert ">=" in filter_str
642+ assert "<=" in filter_str
0 commit comments