1、新增dp策略
This commit is contained in:
@@ -80,6 +80,15 @@ def calculate_metrics(
|
||||
else:
|
||||
calmar_ratio = float("inf")
|
||||
|
||||
target_return = 0
|
||||
downside_returns = df_returns[df_returns < target_return]
|
||||
downside_deviation = downside_returns.std()
|
||||
|
||||
sortino_ratio = 0.0
|
||||
if downside_deviation > 0:
|
||||
# 年化超额收益率 / 年化下行波动率
|
||||
sortino_ratio = np.sqrt(252) * (excess_daily_returns.mean() / downside_deviation)
|
||||
|
||||
total_commissions = sum(t.commission for t in trades)
|
||||
|
||||
# --- 重新计算交易相关指标 ---
|
||||
@@ -139,6 +148,7 @@ def calculate_metrics(
|
||||
"max_drawdown": max_drawdown,
|
||||
"sharpe_ratio": sharpe_ratio,
|
||||
"calmar_ratio": calmar_ratio,
|
||||
"sortino_ratio": sortino_ratio,
|
||||
"total_trades": len(trades), # All buy and sell trades
|
||||
"transaction_costs": total_commissions,
|
||||
"total_realized_pnl": total_realized_pnl, # New
|
||||
|
||||
@@ -46,7 +46,7 @@ class GridSearchAnalyzer:
|
||||
print(f" {self.optimization_metric}: {best_result[self.optimization_metric]:.4f}")
|
||||
return best_result
|
||||
|
||||
def plot_heatmap(self, title: str = "heatmap"):
|
||||
def plot_heatmap(self, title: str = "heatmap", order_direction: str=None):
|
||||
"""
|
||||
绘制两个参数的热力图。
|
||||
"""
|
||||
@@ -59,11 +59,15 @@ class GridSearchAnalyzer:
|
||||
|
||||
heatmap_matrix = np.zeros((len(y_values), len(x_values)))
|
||||
|
||||
max_values = max([item[self.optimization_metric] for item in self.grid_results])
|
||||
# 填充网格
|
||||
for item in self.grid_results:
|
||||
x_idx = x_values.index(item[self.param1_name])
|
||||
y_idx = y_values.index(item[self.param2_name])
|
||||
heatmap_matrix[y_idx, x_idx] = item[self.optimization_metric]
|
||||
if max_values < 0.1:
|
||||
heatmap_matrix[y_idx, x_idx] = item[self.optimization_metric] * 100
|
||||
else:
|
||||
heatmap_matrix[y_idx, x_idx] = item[self.optimization_metric]
|
||||
|
||||
print([x_values[0], x_values[-1], y_values[0], y_values[-1]])
|
||||
fig, ax = plt.subplots(figsize=(10, 8))
|
||||
@@ -76,7 +80,7 @@ class GridSearchAnalyzer:
|
||||
|
||||
ax.set_xlabel(self.param1_name)
|
||||
ax.set_ylabel(self.param2_name)
|
||||
ax.set_title(f"{title}: {self.optimization_metric} vs. {self.param1_name} & {self.param2_name}")
|
||||
ax.set_title(f"{title}: {self.optimization_metric} vs. {self.param1_name} & {self.param2_name}, order={order_direction}")
|
||||
|
||||
cbar = fig.colorbar(im, ax=ax)
|
||||
cbar.set_label(self.optimization_metric)
|
||||
|
||||
@@ -166,6 +166,23 @@ class ResultAnalyzer:
|
||||
# DataFrame 的结构为:['indicator_value', 'realized_pnl']
|
||||
df = pd.DataFrame({"indicator_value": indi_values, "realized_pnl": pnls})
|
||||
|
||||
def remove_extreme(df, col='indicator_value', k=3):
|
||||
"""IQR 稳健过滤,返回过滤后的 df 和被剔除的行数"""
|
||||
q1, q3 = df[col].quantile([0.25, 0.75])
|
||||
iqr = q3 - q1
|
||||
lower, upper = q1 - k * iqr, q3 + k * iqr
|
||||
mask = df[col].between(lower, upper)
|
||||
n_remove = (~mask).sum()
|
||||
return df[mask].copy(), n_remove
|
||||
|
||||
df, n_drop = remove_extreme(df) # 默认 k=2.5
|
||||
if n_drop:
|
||||
print(f"指标 '{indicator_name}' 过滤掉 {n_drop} 个极端异常值 "
|
||||
f"({n_drop / len(df) * 100:.1f}%),剩余 {len(df)} 条样本。")
|
||||
if df.empty:
|
||||
print(f"指标 '{indicator_name}' 过滤后无数据,跳过绘图。")
|
||||
continue
|
||||
|
||||
# 确保数据框不为空
|
||||
if df.empty:
|
||||
print(f"指标 '{indicator_name}' 的数据框为空,跳过绘图。")
|
||||
|
||||
Reference in New Issue
Block a user