@@ -788,3 +788,102 @@ def test_download_all_pairs_history_parallel(mocker, default_conf_usdt):
788788 )
789789 assert result3 == {}
790790 assert exchange .refresh_latest_ohlcv .call_count == 0
791+
792+
793+ def test_download_pair_history_with_pair_candles (mocker , default_conf , tmp_path , caplog ) -> None :
794+ """
795+ Test _download_pair_history with pair_candles parameter (parallel method).
796+ """
797+ exchange = get_patched_exchange (mocker , default_conf )
798+
799+ # Create test data for existing cached data
800+ existing_data = DataFrame (
801+ {
802+ "date" : [dt_utc (2018 , 1 , 10 , 10 , 0 ), dt_utc (2018 , 1 , 10 , 10 , 5 )],
803+ "open" : [1.0 , 1.1 ],
804+ "high" : [1.1 , 1.2 ],
805+ "low" : [0.9 , 1.0 ],
806+ "close" : [1.05 , 1.15 ],
807+ "volume" : [100 , 150 ],
808+ }
809+ )
810+
811+ # Create pair_candles data that will be used instead of exchange download
812+ # This data should start before or at the same time as since_ms to trigger the else branch
813+ pair_candles_data = DataFrame (
814+ {
815+ "date" : [
816+ dt_utc (2018 , 1 , 10 , 10 , 5 ),
817+ dt_utc (2018 , 1 , 10 , 10 , 10 ),
818+ dt_utc (2018 , 1 , 10 , 10 , 15 ),
819+ ],
820+ "open" : [1.15 , 1.2 , 1.25 ],
821+ "high" : [1.25 , 1.3 , 1.35 ],
822+ "low" : [1.1 , 1.15 , 1.2 ],
823+ "close" : [1.2 , 1.25 , 1.3 ],
824+ "volume" : [200 , 250 , 300 ],
825+ }
826+ )
827+
828+ # Mock the data handler to return existing cached data
829+ data_handler_mock = MagicMock ()
830+ data_handler_mock .ohlcv_load .return_value = existing_data
831+ data_handler_mock .ohlcv_store = MagicMock ()
832+ mocker .patch (
833+ "freqtrade.data.history.history_utils.get_datahandler" , return_value = data_handler_mock
834+ )
835+
836+ # Mock _load_cached_data_for_updating to return existing data and since_ms
837+ since_ms = dt_ts (dt_utc (2018 , 1 , 10 , 10 , 5 )) # Time of last existing candle
838+ mocker .patch (
839+ "freqtrade.data.history.history_utils._load_cached_data_for_updating" ,
840+ return_value = (existing_data , since_ms , None ),
841+ )
842+
843+ # Mock clean_ohlcv_dataframe to return concatenated data
844+ expected_result = DataFrame (
845+ {
846+ "date" : [
847+ dt_utc (2018 , 1 , 10 , 10 , 0 ),
848+ dt_utc (2018 , 1 , 10 , 10 , 5 ),
849+ dt_utc (2018 , 1 , 10 , 10 , 10 ),
850+ dt_utc (2018 , 1 , 10 , 10 , 15 ),
851+ ],
852+ "open" : [1.0 , 1.15 , 1.2 , 1.25 ],
853+ "high" : [1.1 , 1.25 , 1.3 , 1.35 ],
854+ "low" : [0.9 , 1.1 , 1.15 , 1.2 ],
855+ "close" : [1.05 , 1.2 , 1.25 , 1.3 ],
856+ "volume" : [100 , 200 , 250 , 300 ],
857+ }
858+ )
859+ mocker .patch (
860+ "freqtrade.data.history.history_utils.clean_ohlcv_dataframe" , return_value = expected_result
861+ )
862+
863+ get_historic_ohlcv_mock = MagicMock ()
864+ mocker .patch .object (exchange , "get_historic_ohlcv" , get_historic_ohlcv_mock )
865+
866+ # Call _download_pair_history with pre-loaded pair_candles
867+ result = _download_pair_history (
868+ datadir = tmp_path ,
869+ exchange = exchange ,
870+ pair = "TEST/BTC" ,
871+ timeframe = "5m" ,
872+ candle_type = CandleType .SPOT ,
873+ pair_candles = pair_candles_data ,
874+ )
875+
876+ # Verify the function succeeded
877+ assert result is True
878+
879+ # Verify that exchange.get_historic_ohlcv was NOT called (parallel method was used)
880+ assert get_historic_ohlcv_mock .call_count == 0
881+
882+ # Verify the log message indicating parallel method was used (line 315-316)
883+ assert log_has ("Downloaded data for TEST/BTC with length 3. Parallel Method." , caplog )
884+
885+ # Verify data was stored
886+ assert data_handler_mock .ohlcv_store .call_count == 1
887+ stored_data = data_handler_mock .ohlcv_store .call_args_list [0 ][1 ]["data" ]
888+ assert stored_data .equals (expected_result )
889+ assert len (stored_data ) == 4
0 commit comments