पोर्टफ़ोलियो लर्निंग के लिए टर्नओवर लागत सहित मज़बूत शार्प लॉस
सारांश
यह मॉड्यूल एंड-टू-एंड पोर्टफ़ोलियो लर्निंग के लिए एक अवकलनीय उद्देश्य परिभाषित करता है। यह वोलैटिलिटी स्केलिंग से परिसंपत्ति-स्तर के सीमित जोखिम वेट को पोर्टफ़ोलियो एक्सपोज़र में बदलता है, उपलब्ध परिसंपत्तियों के औसत सकल रिटर्न की गणना करता है और वैकल्पिक रूप से पिछले वेट में बदलाव के आधार पर लेनदेन लागत घटाता है। रिटर्न श्रृंखला के मूल्यांकन से बर्न-इन अवधि को बाहर रखा जा सकता है।
यह उद्देश्य एक संयुक्त शार्प अनुपात को प्रति-विंडो शार्प अनुपातों के सॉफ्ट न्यूनतम के साथ मिलाता है, जिसे समायोज्य पैरामीटर से भारित किया जाता है; प्रशिक्षण में इस संयुक्त स्कोर का ऋणात्मक मान न्यूनतम किया जाता है। यह संरचना समग्र जोखिम-समायोजित प्रदर्शन को पुरस्कृत करती है और कमज़ोर विंडो को भी ध्यान में रखती है। फ़ंक्शन में वार्षिकीकरण, संख्यात्मक स्थिरीकरण, लागत स्केलिंग और सॉफ्ट-मिन तापमान को समायोजित किया जा सकता है। दस्तावेज़ कार्यान्वयन की परिभाषाएँ देता है, लेकिन अनुभवजन्य नतीजे, अंशांकन मार्गदर्शन या इस बात का प्रमाण नहीं देता कि यह उद्देश्य वास्तविक प्रदर्शन सुधारता है; इसलिए नतीजे वेट, मास्क, लागत और हाइपरपैरामीटर के चुनाव पर निर्भर करते हैं।
मुख्य विचार
- पोर्टफ़ोलियो रिटर्न जोखिम वेट और वोलैटिलिटी स्केलिंग से निकाले जाते हैं तथा हर समय चरण में उपलब्ध परिसंपत्तियों पर उनका औसत लिया जाता है।
- पिछले चरण से पोर्टफ़ोलियो एक्सपोज़र में बदलाव पर दंड लगाकर लेनदेन लागत का मॉडल बनाया जा सकता है।
- लॉस, संयुक्त शार्प को विंडो-स्तर के शार्प अनुपातों के सॉफ्ट न्यूनतम के साथ जोड़ता है।
- शार्प गणना से बर्न-इन के अवलोकन हटाए जा सकते हैं।
- मॉड्यूल एक उद्देश्य परिभाषित करता है, लेकिन अनुभवजन्य प्रमाण या सुझाए गए पैरामीटर मान नहीं देता।
टैग
पूरा पाठ
# 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(),
)
```स्रोत के लाइसेंस के तहत श्रेय सहित पूरा पाठ दिखाया गया है। लाइसेंस: MIT
यह सारांश मूल स्रोत के आधार पर Stratmill के शोध एजेंट ने लिखा है; यह स्रोत की प्रति नहीं है।