@@ -206,14 +206,21 @@ def __post_init__(self):
206206 def to_dict (self ) -> dict :
207207 """
208208 Convert the BacktestMetrics instance to a dictionary.
209+ Ensures all datetime values are serialized to ISO format, but
210+ leaves strings unchanged.
209211
210212 Returns:
211213 dict: A dictionary representation of the BacktestMetrics instance.
212214 """
215+
216+ def ensure_iso (value ):
217+ return value .isoformat () \
218+ if hasattr (value , "isoformat" ) else value
219+
213220 return {
214- "backtest_start_date" : self .backtest_start_date . isoformat ( ),
215- "backtest_end_date" : self .backtest_end_date . isoformat ( ),
216- "equity_curve" : [(value , date . isoformat ( ))
221+ "backtest_start_date" : ensure_iso ( self .backtest_start_date ),
222+ "backtest_end_date" : ensure_iso ( self .backtest_end_date ),
223+ "equity_curve" : [(value , ensure_iso ( date ))
217224 for value , date in self .equity_curve ],
218225 "final_value" : self .final_value ,
219226 "total_net_gain" : self .total_net_gain ,
@@ -223,24 +230,23 @@ def to_dict(self) -> dict:
223230 "total_loss" : self .total_loss ,
224231 "total_loss_percentage" : self .total_loss_percentage ,
225232 "cumulative_return" : self .cumulative_return ,
226- "cumulative_return_series" : [(value , date . isoformat ( ))
233+ "cumulative_return_series" : [(value , ensure_iso ( date ))
227234 for value , date in
228235 self .cumulative_return_series ],
229236 "cagr" : self .cagr ,
230237 "sharpe_ratio" : self .sharpe_ratio ,
231- "rolling_sharpe_ratio" : [
232- (value , date .isoformat ())
233- for value , date in self .rolling_sharpe_ratio
234- ],
238+ "rolling_sharpe_ratio" : [(value , ensure_iso (date ))
239+ for value , date in
240+ self .rolling_sharpe_ratio ],
235241 "sortino_ratio" : self .sortino_ratio ,
236242 "calmar_ratio" : self .calmar_ratio ,
237243 "profit_factor" : self .profit_factor ,
238244 "annual_volatility" : self .annual_volatility ,
239- "monthly_returns" : [(value , date . isoformat ( ))
245+ "monthly_returns" : [(value , ensure_iso ( date ))
240246 for value , date in self .monthly_returns ],
241- "yearly_returns" : [(value , date . isoformat ( ))
247+ "yearly_returns" : [(value , ensure_iso ( date ))
242248 for value , date in self .yearly_returns ],
243- "drawdown_series" : [(value , date . isoformat ( ))
249+ "drawdown_series" : [(value , ensure_iso ( date ))
244250 for value , date in self .drawdown_series ],
245251 "max_drawdown" : self .max_drawdown ,
246252 "max_drawdown_absolute" : self .max_drawdown_absolute ,
@@ -251,25 +257,19 @@ def to_dict(self) -> dict:
251257 "exposure_ratio" : self .exposure_ratio ,
252258 "cumulative_exposure" : self .cumulative_exposure ,
253259 "average_trade_gain" : self .average_trade_gain ,
254- "average_trade_gain_percentage" :
255- self .average_trade_gain_percentage ,
260+ "average_trade_gain_percentage" : self .average_trade_gain_percentage ,
256261 "average_trade_loss" : self .average_trade_loss ,
257- "average_trade_loss_percentage" :
258- self .average_trade_loss_percentage ,
262+ "average_trade_loss_percentage" : self .average_trade_loss_percentage ,
259263 "average_trade_return" : self .average_trade_return ,
260- "average_trade_return_percentage" :
261- self .average_trade_return_percentage ,
264+ "average_trade_return_percentage" : self .average_trade_return_percentage ,
262265 "median_trade_return" : self .median_trade_return ,
263- "median_trade_return_percentage" :
264- self .median_trade_return_percentage ,
266+ "median_trade_return_percentage" : self .median_trade_return_percentage ,
265267 "number_of_positive_trades" : self .number_of_positive_trades ,
266268 "percentage_positive_trades" : self .percentage_positive_trades ,
267269 "number_of_negative_trades" : self .number_of_negative_trades ,
268270 "percentage_negative_trades" : self .percentage_negative_trades ,
269- "best_trade" : self .best_trade .to_dict ()
270- if self .best_trade else None ,
271- "worst_trade" : self .worst_trade .to_dict ()
272- if self .worst_trade else None ,
271+ "best_trade" : self .best_trade .to_dict () if self .best_trade else None ,
272+ "worst_trade" : self .worst_trade .to_dict () if self .worst_trade else None ,
273273 "average_trade_duration" : self .average_trade_duration ,
274274 "average_trade_size" : self .average_trade_size ,
275275 "number_of_trades" : self .number_of_trades ,
@@ -278,10 +278,8 @@ def to_dict(self) -> dict:
278278 "percentage_winning_months" : self .percentage_winning_months ,
279279 "percentage_winning_years" : self .percentage_winning_years ,
280280 "average_monthly_return" : self .average_monthly_return ,
281- "average_monthly_return_losing_months" :
282- self .average_monthly_return_losing_months ,
283- "average_monthly_return_winning_months" :
284- self .average_monthly_return_winning_months ,
281+ "average_monthly_return_losing_months" : self .average_monthly_return_losing_months ,
282+ "average_monthly_return_winning_months" : self .average_monthly_return_winning_months ,
285283 "best_month" : self .best_month ,
286284 "best_year" : self .best_year ,
287285 "worst_month" : self .worst_month ,
0 commit comments