Spaces:
Running
Running
Sync from GitHub (tests passed)
Browse files
deep_learning/models/tft_copper.py
CHANGED
|
@@ -250,21 +250,28 @@ def format_prediction(
|
|
| 250 |
n_days = pred.shape[0]
|
| 251 |
median_idx = len(quantiles) // 2
|
| 252 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
# T+1 quantile spreads (return-space distance from median).
|
| 254 |
# Used as the base width for confidence bands; scaled by sqrt(d) for
|
| 255 |
# later days so uncertainty grows realistically instead of compounding
|
| 256 |
# tail quantiles exponentially (which would produce absurd bands).
|
| 257 |
-
med_0 = float(pred[0, median_idx])
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
|
|
|
| 262 |
|
| 263 |
daily_forecasts = []
|
| 264 |
cum_price_med = baseline_price
|
| 265 |
|
| 266 |
for d in range(n_days):
|
| 267 |
-
med = float(pred[d, median_idx])
|
| 268 |
cum_price_med *= (1 + med)
|
| 269 |
cum_return = (cum_price_med / baseline_price) - 1.0
|
| 270 |
|
|
@@ -288,8 +295,8 @@ def format_prediction(
|
|
| 288 |
|
| 289 |
return {
|
| 290 |
"predicted_return_median": first["daily_return"],
|
| 291 |
-
"predicted_return_q10": float(pred[0, 1]) if len(quantiles) > 2 else first["daily_return"],
|
| 292 |
-
"predicted_return_q90": float(pred[0, -2]) if len(quantiles) > 2 else first["daily_return"],
|
| 293 |
"predicted_price_median": first["price_median"],
|
| 294 |
"predicted_price_q10": first["price_q10"],
|
| 295 |
"predicted_price_q90": first["price_q90"],
|
|
|
|
| 250 |
n_days = pred.shape[0]
|
| 251 |
median_idx = len(quantiles) // 2
|
| 252 |
|
| 253 |
+
# Hard clamp: prevents overconfident models (VR >> 1) from producing
|
| 254 |
+
# absurd compound prices. Copper's actual daily σ ≈ 0.024; capping at
|
| 255 |
+
# ~1.25σ keeps the 5-day compound under ≈16 %. The clamp is inactive
|
| 256 |
+
# once the model is retrained with a healthy VR (0.5–1.5).
|
| 257 |
+
_MAX_DAILY_RET = 0.03
|
| 258 |
+
|
| 259 |
# T+1 quantile spreads (return-space distance from median).
|
| 260 |
# Used as the base width for confidence bands; scaled by sqrt(d) for
|
| 261 |
# later days so uncertainty grows realistically instead of compounding
|
| 262 |
# tail quantiles exponentially (which would produce absurd bands).
|
| 263 |
+
med_0 = float(np.clip(pred[0, median_idx], -_MAX_DAILY_RET, _MAX_DAILY_RET))
|
| 264 |
+
_raw_med_0 = float(pred[0, median_idx])
|
| 265 |
+
spread_q10 = np.clip(float(pred[0, 1]) - _raw_med_0, -_MAX_DAILY_RET, 0) if len(quantiles) > 2 else 0.0
|
| 266 |
+
spread_q90 = np.clip(float(pred[0, -2]) - _raw_med_0, 0, _MAX_DAILY_RET) if len(quantiles) > 2 else 0.0
|
| 267 |
+
spread_q02 = np.clip(float(pred[0, 0]) - _raw_med_0, -_MAX_DAILY_RET * 1.5, 0)
|
| 268 |
+
spread_q98 = np.clip(float(pred[0, -1]) - _raw_med_0, 0, _MAX_DAILY_RET * 1.5)
|
| 269 |
|
| 270 |
daily_forecasts = []
|
| 271 |
cum_price_med = baseline_price
|
| 272 |
|
| 273 |
for d in range(n_days):
|
| 274 |
+
med = float(np.clip(pred[d, median_idx], -_MAX_DAILY_RET, _MAX_DAILY_RET))
|
| 275 |
cum_price_med *= (1 + med)
|
| 276 |
cum_return = (cum_price_med / baseline_price) - 1.0
|
| 277 |
|
|
|
|
| 295 |
|
| 296 |
return {
|
| 297 |
"predicted_return_median": first["daily_return"],
|
| 298 |
+
"predicted_return_q10": float(np.clip(pred[0, 1], -_MAX_DAILY_RET * 2, _MAX_DAILY_RET * 2)) if len(quantiles) > 2 else first["daily_return"],
|
| 299 |
+
"predicted_return_q90": float(np.clip(pred[0, -2], -_MAX_DAILY_RET * 2, _MAX_DAILY_RET * 2)) if len(quantiles) > 2 else first["daily_return"],
|
| 300 |
"predicted_price_median": first["price_median"],
|
| 301 |
"predicted_price_q10": first["price_q10"],
|
| 302 |
"predicted_price_q90": first["price_q90"],
|