Hàm mất mát Sharpe bền vững có chi phí vòng quay cho học danh mục
Tóm tắt
Mô-đun này định nghĩa một hàm mục tiêu khả vi cho việc học danh mục đầu tư từ đầu đến cuối. Hàm chuyển trọng số rủi ro bị giới hạn ở cấp tài sản thành mức độ phơi nhiễm danh mục bằng cách điều chỉnh theo biến động, tính lợi suất gộp trung bình trên các tài sản hiện có, và tùy chọn trừ chi phí giao dịch dựa trên thay đổi so với trọng số trước đó. Có thể loại trừ giai đoạn khởi động khỏi việc đánh giá chuỗi lợi suất.
Hàm mục tiêu kết hợp tỷ lệ Sharpe gộp với mức tối thiểu mềm của các tỷ lệ Sharpe theo cửa sổ, có trọng số bởi một tham số có thể điều chỉnh; quá trình huấn luyện tối thiểu hóa giá trị âm của điểm kết hợp đó. Cấu trúc này thưởng cho hiệu suất tổng thể đã điều chỉnh theo rủi ro, đồng thời tính đến các cửa sổ yếu hơn. Các hàm cho phép cấu hình quy đổi năm, ổn định số học, tỷ lệ chi phí và nhiệt độ của mức tối thiểu mềm. Tài liệu cung cấp định nghĩa triển khai nhưng không có kết quả thực nghiệm, hướng dẫn hiệu chỉnh hay bằng chứng rằng hàm mục tiêu cải thiện hiệu suất thực tế; kết quả do đó phụ thuộc vào lựa chọn trọng số, mặt nạ, chi phí và siêu tham số.
Ý chính
- Lợi suất danh mục được tính từ trọng số rủi ro và điều chỉnh theo biến động, rồi lấy trung bình trên các tài sản hiện có tại mỗi bước thời gian.
- Có thể mô hình hóa chi phí giao dịch như khoản phạt cho thay đổi mức độ phơi nhiễm danh mục so với bước trước đó.
- Hàm mất mát kết hợp Sharpe gộp với mức tối thiểu mềm của tỷ lệ Sharpe theo từng cửa sổ.
- Có thể loại trừ các quan sát trong giai đoạn khởi động khỏi phép tính Sharpe.
- Mô-đun định nghĩa một hàm mục tiêu nhưng không đưa ra bằng chứng thực nghiệm hay giá trị tham số được khuyến nghị.
Thẻ
Toàn văn
# losses.py
```py
"""Loss functions for DeePM-style end-to-end portfolio learning."""
from __future__ import annotations
from dataclasses import dataclass
import torch
@dataclass(frozen=True, slots=True)
class LossOutput:
"""Outputs returned by the robust Sharpe loss."""
loss: torch.Tensor
sharpe_pool: torch.Tensor
softmin_sharpe: torch.Tensor
objective: torch.Tensor
net_returns: torch.Tensor
def compute_net_portfolio_returns(
*,
p: torch.Tensor,
y_fwd1: torch.Tensor,
vol_scale: torch.Tensor,
mask: torch.Tensor,
costs: torch.Tensor | None,
gamma_cost: float,
) -> torch.Tensor:
"""Compute net portfolio returns (Eq. 13).
Parameters
----------
p: Risk weights in (-1, 1), shape (B, T, N).
y_fwd1: Vol-scaled forward returns, shape (B, T, N).
vol_scale: Volatility scaling, shape (B, T, N).
mask: Availability mask, shape (B, T, N).
costs: Per-asset cost coefficients, shape (N,) or (N, 1). None to skip.
gamma_cost: Global cost scaling factor.
Returns
-------
Net portfolio return series, shape (B, T).
"""
b, t, n = p.shape
w = vol_scale * p
w_prev = torch.cat(
[torch.zeros((b, 1, n), device=w.device, dtype=w.dtype), w[:, :-1, :]], dim=1
)
gross = (mask * p * y_fwd1).sum(dim=-1)
n_t = mask.sum(dim=-1).clamp(min=1.0)
gross = gross / n_t
if costs is None:
return gross
if (costs.ndim == 2 and costs.shape[1] == 1) or (costs.ndim == 1 and costs.shape[0] == n):
c = costs.view(1, 1, n)
else:
raise ValueError("costs must have shape (N,) or (N,1)")
turnover = torch.abs(w - w_prev)
cost = (mask * c * turnover).sum(dim=-1)
cost = (gamma_cost * cost) / n_t
return gross - cost
def sharpe_ratio(
returns: torch.Tensor,
*,
annualization_factor: float,
eps: float,
dim: int | None = None,
) -> torch.Tensor:
"""Compute a differentiable Sharpe ratio."""
if dim is None:
mu = returns.mean()
var = returns.var(unbiased=False)
else:
mu = returns.mean(dim=dim)
var = returns.var(dim=dim, unbiased=False)
return (annualization_factor**0.5) * mu / torch.sqrt(var + eps)
def softmin_sharpe(
window_sharpes: torch.Tensor,
*,
tau: float,
) -> torch.Tensor:
"""Soft minimum of window-wise Sharpe ratios (Eq. 33)."""
return -tau * torch.log(torch.mean(torch.exp(-window_sharpes / tau)))
def robust_sharpe_loss(
*,
p: torch.Tensor,
y_fwd1: torch.Tensor,
vol_scale: torch.Tensor,
mask: torch.Tensor,
costs: torch.Tensor | None,
burn_in: int,
gamma_cost: float,
annualization_factor: float,
eps: float,
tau: float,
lambda_soft: float,
) -> LossOutput:
"""Compute DeePM robust objective loss (Eq. 31).
L(theta) = - SR_pool(R) - lambda * SoftMin_tau({SR_b}).
"""
net_r = compute_net_portfolio_returns(
p=p,
y_fwd1=y_fwd1,
vol_scale=vol_scale,
mask=mask,
costs=costs,
gamma_cost=gamma_cost,
)
net_r_eff = net_r[:, burn_in:] if burn_in > 0 else net_r
sr_pool = sharpe_ratio(
net_r_eff.reshape(-1), annualization_factor=annualization_factor, eps=eps
)
sr_windows = sharpe_ratio(net_r_eff, annualization_factor=annualization_factor, eps=eps, dim=1)
sr_softmin = softmin_sharpe(sr_windows, tau=tau)
objective = sr_pool + lambda_soft * sr_softmin
loss = -objective
return LossOutput(
loss=loss,
sharpe_pool=sr_pool.detach(),
softmin_sharpe=sr_softmin.detach(),
objective=objective.detach(),
net_returns=net_r.detach(),
)
```Hiển thị toàn văn kèm ghi nguồn theo giấy phép của tài liệu gốc. Giấy phép: MIT
Bản tóm tắt này do tác nhân nghiên cứu của Stratmill biên soạn từ tài liệu gốc; đây không phải bản sao của tài liệu.