@@ -506,3 +506,70 @@ def test_get_datahandler(testdatadir):
506506 assert isinstance (dh , JsonGzDataHandler )
507507 dh1 = get_datahandler (testdatadir , "jsongz" , dh )
508508 assert id (dh1 ) == id (dh )
509+
510+
511+ @pytest .fixture
512+ def feather_dh (testdatadir ):
513+ return FeatherDataHandler (testdatadir )
514+
515+
516+ @pytest .fixture
517+ def trades_full (feather_dh ):
518+ df = feather_dh .trades_load ("XRP/ETH" , TradingMode .SPOT )
519+ assert not df .empty
520+ return df
521+
522+
523+ @pytest .fixture
524+ def timerange_full (trades_full ):
525+ # Pick a full-span window using actual timestamps
526+ startts = int (trades_full ["timestamp" ].min ())
527+ stopts = int (trades_full ["timestamp" ].max ())
528+ return TimeRange ("date" , "date" , startts = startts , stopts = stopts )
529+
530+
531+ @pytest .fixture
532+ def timerange_mid (trades_full ):
533+ # Pick a mid-range window using actual timestamps
534+ mid_start = int (trades_full ["timestamp" ].iloc [len (trades_full ) // 3 ])
535+ mid_end = int (trades_full ["timestamp" ].iloc [(2 * len (trades_full )) // 3 ])
536+ return TimeRange ("date" , "date" , startts = mid_start , stopts = mid_end )
537+
538+
539+ def test_feather_trades_timerange_filter_fullspan (feather_dh , trades_full , timerange_full ):
540+ # Full-span filter should equal unfiltered
541+ filtered = feather_dh .trades_load ("XRP/ETH" , TradingMode .SPOT , timerange = timerange_full )
542+ assert_frame_equal (
543+ trades_full .reset_index (drop = True ), filtered .reset_index (drop = True ), check_exact = True
544+ )
545+
546+
547+ def test_feather_trades_timerange_filter_subset (feather_dh , trades_full , timerange_mid ):
548+ # Subset filter should be a subset of the full-span filter
549+ subset = feather_dh .trades_load ("XRP/ETH" , TradingMode .SPOT , timerange = timerange_mid )
550+ assert not subset .empty
551+ assert subset ["timestamp" ].min () >= timerange_mid .startts
552+ assert subset ["timestamp" ].max () <= timerange_mid .stopts
553+ assert len (subset ) < len (trades_full )
554+
555+
556+ def test_feather_trades_timerange_pushdown_fallback (
557+ feather_dh , trades_full , timerange_mid , monkeypatch , caplog
558+ ):
559+ # Pushdown filter should fail, so fallback should load the entire file
560+ import freqtrade .data .history .datahandlers .featherdatahandler as fdh
561+
562+ def raise_err (* args , ** kwargs ):
563+ raise ValueError ("fail" )
564+
565+ # Mock the dataset loading to raise an error
566+ monkeypatch .setattr (fdh .dataset , "dataset" , raise_err )
567+
568+ with caplog .at_level ("WARNING" ):
569+ out = feather_dh .trades_load ("XRP/ETH" , TradingMode .SPOT , timerange = timerange_mid )
570+
571+ assert len (out ) == len (trades_full )
572+ assert any (
573+ "Unable to use Arrow filtering, loading entire trades file" in r .message
574+ for r in caplog .records
575+ )
0 commit comments