Skip to content

Commit c2657cf

Browse files
committed
Fix filter function
1 parent f402c09 commit c2657cf

File tree

6 files changed

+115
-76
lines changed

6 files changed

+115
-76
lines changed

investing_algorithm_framework/app/analysis/backtest_utils.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
from logging import getLogger
55
from random import Random
66

7-
from investing_algorithm_framework.domain import Backtest
7+
from investing_algorithm_framework.domain import Backtest, \
8+
OperationalException
89

910

1011
logger = getLogger("investing_algorithm_framework")
@@ -57,8 +58,18 @@ def save_backtests_to_directory(
5758
if dir_name_generation_function is not None:
5859
dir_name = dir_name_generation_function(backtest)
5960
else:
61+
62+
if backtest.algorithm_id is None:
63+
raise OperationalException(
64+
"algorithm_id is not set in backtest instance,"
65+
"cannot generate directory name automatically, "
66+
"please make sure to set the algorithm_id field "
67+
"in your strategies or provide "
68+
"a dir_name_generation_function."
69+
)
70+
6071
# Check if there is an ID in the backtest metadata
61-
dir_name = backtest.metadata.get('id', None)
72+
dir_name = backtest.algorithm_id
6273

6374
if dir_name is None:
6475
logger.warning(

investing_algorithm_framework/app/app.py

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,13 +1022,13 @@ def filter_function(
10221022
that was backtested.
10231023
"""
10241024
backtests = []
1025-
strategy_ids = [strategy.id for strategy in strategies]
1026-
strategy_id_selection = strategy_ids.copy()
1025+
algorithm_ids = [strategy.algorithm_id for strategy in strategies]
1026+
algorithm_ids_selection = algorithm_ids.copy()
10271027
data_sources = []
10281028

10291029
# Only used when backtest_storage_directory is None and
10301030
# backtest_date_ranges is provided
1031-
backtests_ordered_by_strategy = {}
1031+
backtests_ordered_by_algorithm = {}
10321032

10331033
if backtest_date_range is None and backtest_date_ranges is None:
10341034
raise OperationalException(
@@ -1052,7 +1052,6 @@ def filter_function(
10521052
)
10531053

10541054
if backtest_date_range is not None:
1055-
backtest_results = []
10561055
if not skip_data_sources_initialization:
10571056
self.initialize_data_sources_backtest(
10581057
data_sources,
@@ -1076,6 +1075,7 @@ def filter_function(
10761075
continue_on_error=continue_on_error,
10771076
use_checkpoints=use_checkpoints,
10781077
backtest_storage_directory=backtest_storage_directory,
1078+
show_progress=False,
10791079
)
10801080
)
10811081

@@ -1145,7 +1145,8 @@ def filter_function(
11451145
use_checkpoints=use_checkpoints,
11461146
backtest_storage_directory=(
11471147
backtest_storage_directory
1148-
)
1148+
),
1149+
show_progress=False
11491150
)
11501151
)
11511152

@@ -1155,13 +1156,12 @@ def filter_function(
11551156
backtest_results = filter_function(
11561157
backtest_results, backtest_date_range
11571158
)
1158-
strategy_id_selection = [
1159-
backtest.metadata["id"] for backtest
1160-
in backtest_results
1159+
algorithm_ids_selection = [
1160+
backtest.algorithm_id for backtest in backtest_results
11611161
]
11621162
active_strategies = [
11631163
strategy for strategy in active_strategies
1164-
if strategy.id in strategy_id_selection
1164+
if strategy.algorithm_id in algorithm_ids_selection
11651165
]
11661166

11671167
# Save the intermediate backtests to a temp storage location
@@ -1174,8 +1174,8 @@ def filter_function(
11741174

11751175
else:
11761176
for backtest in backtest_results:
1177-
backtests_ordered_by_strategy.setdefault(
1178-
backtest.metadata["id"], []
1177+
backtests_ordered_by_algorithm.setdefault(
1178+
backtest.algorithm_id, []
11791179
).append(backtest)
11801180

11811181
del backtest_results
@@ -1184,40 +1184,38 @@ def filter_function(
11841184
gc.collect()
11851185

11861186
def load_backtest_filter_fn(bt: Backtest) -> bool:
1187-
return bt.metadata["id"] in strategy_id_selection
1187+
return bt.algorithm_id in algorithm_ids_selection
11881188

11891189
# load all backtests from storage directories and combine them
11901190
if backtest_storage_directory is not None:
1191-
strategy_id_selection = [
1192-
strategy.id for strategy in active_strategies
1193-
]
11941191
for backtest_range in storage_directories:
1195-
11961192
path = storage_directories[backtest_range]
11971193
loaded_backtests = load_backtests_from_directory(
11981194
directory_path=path,
11991195
filter_function=load_backtest_filter_fn
12001196
)
12011197

12021198
for backtest in loaded_backtests:
1203-
backtests_ordered_by_strategy.setdefault(
1204-
backtest.metadata["id"], []
1199+
backtests_ordered_by_algorithm.setdefault(
1200+
backtest.algorithm_id, []
12051201
).append(backtest)
12061202

12071203
# Remove all temp storage directories
12081204
shutil.rmtree(path)
12091205
else:
12101206
# Remove all strategies that are not in the final selection
1211-
backtests_ordered_by_strategy = {
1212-
strategy_id: backtests
1213-
for strategy_id, backtests in
1214-
backtests_ordered_by_strategy.items()
1215-
if strategy_id in strategy_id_selection
1207+
backtests_ordered_by_algorithm = {
1208+
algorithm_id: backtests
1209+
for algorithm_id, backtests in
1210+
backtests_ordered_by_algorithm.items()
1211+
if algorithm_id in algorithm_ids_selection
12161212
}
12171213

1218-
for strategy in backtests_ordered_by_strategy:
1214+
for algorith_id in backtests_ordered_by_algorithm.keys():
12191215
backtests.append(
1220-
combine_backtests(backtests_ordered_by_strategy[strategy])
1216+
combine_backtests(
1217+
backtests_ordered_by_algorithm[algorith_id]
1218+
)
12211219
)
12221220

12231221
if backtest_storage_directory is not None:
@@ -1237,18 +1235,18 @@ def run_vector_backtest(
12371235
metadata: Optional[Dict[str, str]] = None,
12381236
risk_free_rate: Optional[float] = None,
12391237
skip_data_sources_initialization: bool = False,
1240-
show_data_initialization_progress: bool = True,
12411238
initial_amount: float = None,
12421239
market: str = None,
12431240
trading_symbol: str = None,
12441241
continue_on_error: bool = False,
12451242
backtest_storage_directory: Optional[Union[str, Path]] = None,
1246-
use_checkpoints: bool = True
1243+
use_checkpoints: bool = False,
1244+
show_progress=False,
12471245
) -> Backtest:
12481246
"""
12491247
Run vectorized backtests for a strategy. The provided
1250-
strategy needs to have its 'buy_signal_vectorized' and
1251-
'sell_signal_vectorized' methods implemented to support vectorized
1248+
strategy needs to have its 'generate_buy_signals' and
1249+
'generate_sell_signals' methods implemented to support vectorized
12521250
backtesting.
12531251
12541252
Args:
@@ -1279,8 +1277,6 @@ def run_vector_backtest(
12791277
initialization step. This will speed up the backtesting
12801278
process, but make sure that the data sources are already
12811279
initialized before calling this method.
1282-
show_data_initialization_progress (bool): Whether to show the
1283-
progress bar when initializing data sources.
12841280
market (str): The market to use for the backtest. This is used
12851281
to create a portfolio configuration if no portfolio
12861282
configuration is provided in the strategy.
@@ -1307,6 +1303,9 @@ def run_vector_backtest(
13071303
backtest exists, it will be loaded
13081304
instead of running a new backtest. This is useful for
13091305
long-running backtests that might take a while to complete.
1306+
show_progress (bool): Whether to show progress bars during
1307+
data source initialization. This is useful for long-running
1308+
initialization processes.
13101309
13111310
Returns:
13121311
Backtest: Instance of Backtest
@@ -1328,7 +1327,7 @@ def run_vector_backtest(
13281327
self.initialize_data_sources_backtest(
13291328
strategy.data_sources,
13301329
backtest_date_range,
1331-
show_progress=show_data_initialization_progress
1330+
show_progress=show_progress
13321331
)
13331332

13341333
if risk_free_rate is None:
@@ -1360,6 +1359,16 @@ def run_vector_backtest(
13601359
)
13611360
else:
13621361
try:
1362+
1363+
if show_progress:
1364+
start_date = backtest_date_range \
1365+
.start_date.strftime('%Y-%m-%d')
1366+
end_date = backtest_date_range.end_date.strftime(
1367+
'%Y-%m-%d')
1368+
print(
1369+
f"Running backtests for {start_date} to {end_date}"
1370+
)
1371+
13631372
run = backtest_service.create_vector_backtest(
13641373
strategy=strategy,
13651374
backtest_date_range=backtest_date_range,
@@ -1369,6 +1378,7 @@ def run_vector_backtest(
13691378
initial_amount=initial_amount
13701379
)
13711380
backtest = Backtest(
1381+
algorithm_id=strategy.algorithm_id,
13721382
backtest_runs=[run],
13731383
risk_free_rate=risk_free_rate,
13741384
backtest_summary=generate_backtest_summary_metrics(
@@ -1380,8 +1390,10 @@ def run_vector_backtest(
13801390
f"Error occurred during vector backtest for strategy "
13811391
f"{strategy.strategy_id}: {str(e)}"
13821392
)
1393+
13831394
if continue_on_error:
13841395
backtest = Backtest(
1396+
algorithm_id=strategy.algorithm_id,
13851397
backtest_runs=[],
13861398
risk_free_rate=risk_free_rate,
13871399
)

investing_algorithm_framework/app/strategy.py

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class TradingStrategy:
5252

5353
def __init__(
5454
self,
55-
id,
55+
algorithm_id=None,
5656
strategy_id=None,
5757
time_unit=None,
5858
interval=None,
@@ -66,7 +66,29 @@ def __init__(
6666
worker_id=None,
6767
decorated=None
6868
):
69-
self.id = id
69+
if metadata is None:
70+
metadata = {}
71+
72+
self.metadata = metadata
73+
74+
if worker_id is not None:
75+
self.worker_id = worker_id
76+
elif self.decorated:
77+
self.worker_id = decorated.__name__
78+
else:
79+
self.worker_id = self.__class__.__name__
80+
81+
if strategy_id is not None:
82+
self.strategy_id = strategy_id
83+
else:
84+
self.strategy_id = self.worker_id
85+
86+
if algorithm_id is not None:
87+
self.algorithm_id = algorithm_id
88+
89+
if "algorithm_id" in self.metadata:
90+
self.algorithm_id = self.metadata["algorithm_id"]
91+
7092
if time_unit is not None:
7193
self.time_unit = TimeUnit.from_value(time_unit)
7294
else:
@@ -85,29 +107,9 @@ def __init__(
85107
if data_sources is not None:
86108
self.data_sources = data_sources
87109

88-
if metadata is None:
89-
metadata = {}
90-
91-
self.metadata = metadata
92-
93-
if "id" not in self.metadata:
94-
self.metadata["id"] = self.id
95-
96110
if decorated is not None:
97111
self.decorated = decorated
98112

99-
if worker_id is not None:
100-
self.worker_id = worker_id
101-
elif self.decorated:
102-
self.worker_id = decorated.__name__
103-
else:
104-
self.worker_id = self.__class__.__name__
105-
106-
if strategy_id is not None:
107-
self.strategy_id = strategy_id
108-
else:
109-
self.strategy_id = self.worker_id
110-
111113
if position_sizes is not None:
112114
self.position_sizes = position_sizes
113115

0 commit comments

Comments
 (0)