@@ -844,9 +844,12 @@ def run_vector_backtests_with_checkpoints(
844844 market : Optional [str ] = None ,
845845 trading_symbol : Optional [str ] = None ,
846846 continue_on_error : bool = False ,
847- filter_function : Optional [
847+ window_filter_function : Optional [
848848 Callable [[List [Backtest ], BacktestDateRange ], List [Backtest ]]
849849 ] = None ,
850+ final_filter_function : Optional [
851+ Callable [[List [Backtest ]], List [Backtest ]]
852+ ] = None ,
850853 backtest_storage_directory : Optional [Union [str , Path ]] = None ,
851854 ):
852855 """
@@ -863,7 +866,7 @@ def run_vector_backtests_with_checkpoints(
863866 initialization of data sources.
864867 show_progress (bool): Whether to show a progress bar and
865868 debug for the different processing steps.
866- filter_function (
869+ window_filter_function (
867870 Optional[Callable[[List[Backtest], BacktestDateRange],
868871 List[Backtest]]]
869872 ):
@@ -881,6 +884,20 @@ def filter_function(
881884 backtests: List[Backtest],
882885 backtest_date_range: BacktestDateRange
883886 ) -> List[Backtest]
887+ final_filter_function (
888+ Optional[Callable[[List[Backtest]], List[Backtest]]]
889+ ):
890+ A function that takes a list of Backtest objects and
891+ returns a filtered list of Backtest objects. This is applied
892+ after all backtest date ranges have been processed when
893+ backtest_date_ranges is provided. Only the strategies from
894+ the filtered backtests will be returned as the final result.
895+ This allows for final filtering of strategies based on
896+ their overall performance across all periods. The function
897+ signature should be:
898+ def filter_function(
899+ backtests: List[Backtest]
900+ ) -> List[Backtest]
884901 Returns:
885902 None
886903 """
@@ -954,7 +971,9 @@ def filter_function(
954971 missing_backtests = []
955972
956973 for strategy in tqdm (
957- strategies , colour = "green" , desc = "Running backtests"
974+ strategies ,
975+ colour = "green" ,
976+ desc = f"{ GREEN_COLOR } Running backtests{ COLOR_RESET } "
958977 ):
959978 missing_backtests .append (
960979 self .run_vector_backtest (
@@ -974,9 +993,15 @@ def filter_function(
974993
975994 backtests .extend (missing_backtests )
976995
977- # Apply filter function if set
978- if filter_function is not None :
979- backtests = filter_function (backtests , backtest_date_range )
996+ # Apply window filter function if set
997+ if window_filter_function is not None :
998+ backtests = window_filter_function (
999+ backtests , backtest_date_range
1000+ )
1001+
1002+ # Apply final filter function if set
1003+ if final_filter_function is not None :
1004+ backtests = final_filter_function (backtests )
9801005
9811006 backtests_to_be_saved = [
9821007 bt for bt in missing_backtests if bt in backtests
@@ -1012,7 +1037,8 @@ def filter_function(
10121037 for backtest_date_range in tqdm (
10131038 backtest_date_ranges ,
10141039 colour = "green" ,
1015- desc = "Running backtests for all date ranges"
1040+ desc = f"{ GREEN_COLOR } Running backtests for "
1041+ f"all date ranges{ COLOR_RESET } "
10161042 ):
10171043 if not skip_data_sources_initialization :
10181044 self .initialize_data_sources_backtest (
@@ -1055,7 +1081,7 @@ def filter_function(
10551081 else :
10561082 print (
10571083 GREEN_COLOR +
1058- f"Found { len (backtest_results )} checkpoints, " +
1084+ f"Found { len (backtest_results )} checkpoints. " +
10591085 COLOR_RESET
10601086 )
10611087
@@ -1064,8 +1090,9 @@ def filter_function(
10641090 for strategy in tqdm (
10651091 strategies_to_run ,
10661092 colour = "green" ,
1067- desc = f"Running backtests for { start_date } "
1068- f"to { end_date } "
1093+ desc = f"{ GREEN_COLOR } Running backtests "
1094+ f"for { start_date } "
1095+ f"to { end_date } { COLOR_RESET } "
10691096 ):
10701097 backtest_results .append (
10711098 self .run_vector_backtest (
@@ -1086,8 +1113,8 @@ def filter_function(
10861113
10871114 # Apply filter function after each date range to determine
10881115 # which strategies continue to the next period
1089- if filter_function is not None :
1090- backtest_results = filter_function (
1116+ if window_filter_function is not None :
1117+ backtest_results = window_filter_function (
10911118 backtest_results , backtest_date_range
10921119 )
10931120 active_algorithm_ids = [
@@ -1128,6 +1155,10 @@ def filter_function(
11281155 )
11291156 )
11301157
1158+ # Apply final filter function if set
1159+ if final_filter_function is not None :
1160+ backtests = final_filter_function (backtests )
1161+
11311162 if show_progress :
11321163 print (GREEN_COLOR + "Saving all backtests ..." + COLOR_RESET )
11331164
@@ -1159,9 +1190,12 @@ def run_vector_backtests(
11591190 market : Optional [str ] = None ,
11601191 trading_symbol : Optional [str ] = None ,
11611192 continue_on_error : bool = False ,
1162- filter_function : Optional [
1193+ window_filter_function : Optional [
11631194 Callable [[List [Backtest ], BacktestDateRange ], List [Backtest ]]
11641195 ] = None ,
1196+ final_filter_function : Optional [
1197+ Callable [[List [Backtest ]], List [Backtest ]]
1198+ ] = None ,
11651199 backtest_storage_directory : Optional [Union [str , Path ]] = None ,
11661200 ):
11671201 """
@@ -1178,7 +1212,7 @@ def run_vector_backtests(
11781212 initialization of data sources.
11791213 show_progress (bool): Whether to show a progress bar and
11801214 debug for the different processing steps.
1181- filter_function (
1215+ window_filter_function (
11821216 Optional[Callable[[List[Backtest], BacktestDateRange],
11831217 List[Backtest]]]
11841218 ):
@@ -1196,6 +1230,20 @@ def filter_function(
11961230 backtests: List[Backtest],
11971231 backtest_date_range: BacktestDateRange
11981232 ) -> List[Backtest]
1233+ final_filter_function (
1234+ Optional[Callable[[List[Backtest]], List[Backtest]]]
1235+ ):
1236+ A function that takes a list of Backtest objects and
1237+ returns a filtered list of Backtest objects. This is applied
1238+ after all backtest date ranges have been processed when
1239+ backtest_date_ranges is provided. Only the strategies from
1240+ the filtered backtests will be returned as the final result.
1241+ This allows for final filtering of strategies based on
1242+ their overall performance across all periods. The function
1243+ signature should be:
1244+ def filter_function(
1245+ backtests: List[Backtest]
1246+ ) -> List[Backtest]
11991247 Returns:
12001248 None
12011249 """
@@ -1240,7 +1288,9 @@ def filter_function(
12401288 backtests = []
12411289
12421290 for strategy in tqdm (
1243- strategies , colour = "green" , desc = "Running backtests"
1291+ strategies ,
1292+ colour = "green" ,
1293+ desc = f"{ GREEN_COLOR } Running backtests{ COLOR_RESET } "
12441294 ):
12451295 backtests .append (
12461296 self .run_vector_backtest (
@@ -1259,8 +1309,14 @@ def filter_function(
12591309 )
12601310
12611311 # Apply filter function if set
1262- if filter_function is not None :
1263- backtests = filter_function (backtests , backtest_date_range )
1312+ if window_filter_function is not None :
1313+ backtests = window_filter_function (
1314+ backtests , backtest_date_range
1315+ )
1316+
1317+ # Apply final filter function if set
1318+ if final_filter_function is not None :
1319+ backtests = final_filter_function (backtests )
12641320
12651321 if show_progress :
12661322 print (
@@ -1293,7 +1349,8 @@ def filter_function(
12931349 for backtest_date_range in tqdm (
12941350 backtest_date_ranges ,
12951351 colour = "green" ,
1296- desc = "Running backtests for all date ranges"
1352+ desc = f"{ GREEN_COLOR } Running backtests "
1353+ f"for all date ranges{ COLOR_RESET } "
12971354 ):
12981355
12991356 if not skip_data_sources_initialization :
@@ -1312,7 +1369,8 @@ def filter_function(
13121369 for strategy in tqdm (
13131370 strategies ,
13141371 colour = "green" ,
1315- desc = f"Running backtests for { start_date } to { end_date } "
1372+ desc = f"{ GREEN_COLOR } Running backtests "
1373+ f"for { start_date } to { end_date } { COLOR_RESET } "
13161374 ):
13171375 backtest_results .append (
13181376 self .run_vector_backtest (
@@ -1330,8 +1388,8 @@ def filter_function(
13301388
13311389 # Apply filter function after each date range to determine
13321390 # which strategies continue to the next period
1333- if filter_function is not None :
1334- backtest_results = filter_function (
1391+ if window_filter_function is not None :
1392+ backtest_results = window_filter_function (
13351393 backtest_results , backtest_date_range
13361394 )
13371395 active_algorithm_ids = [
@@ -1372,6 +1430,10 @@ def filter_function(
13721430 )
13731431 )
13741432
1433+ # Apply final filter function if set
1434+ if final_filter_function is not None :
1435+ backtests = final_filter_function (backtests )
1436+
13751437 if backtest_storage_directory is not None :
13761438 if show_progress :
13771439 print (
0 commit comments