87 lines
3 KiB
Python
87 lines
3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Uji region klasik GARCH + winsorize pada return padat-train XAUUSD M15."""
|
|
import os
|
|
import sys
|
|
import math
|
|
import numpy as np
|
|
import datetime as dt
|
|
from scipy.optimize import minimize
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
SRC = os.path.normpath(os.path.join(HERE, "..", "..", "SniperGold_ML"))
|
|
sys.path.insert(0, SRC)
|
|
import train_regime as TR
|
|
|
|
BASE = os.path.normpath(os.path.join(HERE, "..", "..", "..", "Files", "AlgoForge", "Data"))
|
|
z = np.load(os.path.join(BASE, "XAUUSD_M15.npz"))
|
|
t = z["time"].astype(np.int64)
|
|
c = z["close"].astype(np.float64)
|
|
r = np.zeros(len(c))
|
|
r[1:] = np.log(np.maximum(c[1:], 1e-12) / np.maximum(c[:-1], 1e-12))
|
|
|
|
lo = int(np.argmax(t >= dt.datetime(2018, 1, 1).timestamp()))
|
|
hi = int(np.argmax(t > dt.datetime(2024, 7, 30).timestamp()))
|
|
rr = r[lo:hi].copy()
|
|
n = len(rr)
|
|
var0 = float(np.var(rr) + 1e-12)
|
|
rl = [float(x) for x in rr]
|
|
|
|
|
|
def negll_p(p, data):
|
|
w, a, b, nu = p
|
|
if w <= 0 or a < 0 or b < 0 or a + b >= 0.999 or nu <= 2.05:
|
|
return 1e12
|
|
l1 = math.log(math.pi * (nu - 2.0))
|
|
l2 = 2.0 * math.lgamma(nu / 2.0) - 2.0 * math.lgamma((nu + 1.0) / 2.0)
|
|
s2 = var0
|
|
ll = 0.0
|
|
for rv in data:
|
|
s2 = w + a * rv * rv + b * s2
|
|
if s2 < 1e-12:
|
|
s2 = 1e-12
|
|
e2 = rv * rv / s2
|
|
ll += math.log(s2) + (nu + 1.0) * math.log1p(e2 / (nu - 2.0))
|
|
return 0.5 * (ll + len(data) * (l1 + l2))
|
|
|
|
|
|
def fit(data, x0, bnd, tag, winsor=None):
|
|
d = np.clip(data, -winsor, winsor) if winsor else data
|
|
res = minimize(negll_p, x0, args=(d,), method="L-BFGS-B", bounds=bnd,
|
|
options=dict(maxiter=4000))
|
|
w, a, b, nu = res.x
|
|
print(f" [{tag}] omega={w:.3e} alpha={a:.4f} beta={b:.4f} "
|
|
f"persist={a+b:.4f} nu={nu:.2f} nfev={res.nfev}")
|
|
return res.x
|
|
|
|
|
|
print(f"data: n={n} std={rr.std():.6f} |r|max={np.abs(rr).max():.4f} "
|
|
f"|r|>1%: {int((np.abs(rr) > 0.01).sum())}")
|
|
|
|
CLS = [(1e-10, 1e-4), (0.001, 0.15), (0.80, 0.98), (2.1, 30.0)]
|
|
X0 = [1e-7, 0.06, 0.92, 7.0]
|
|
|
|
print("\nA. region klasik (alpha<=0.15, beta>=0.80):")
|
|
fit(rr, X0, CLS, "klasik, data penuh")
|
|
for wl in (0.01, 0.005):
|
|
fit(rr, X0, CLS, f"klasik, winsor={wl}", winsor=wl)
|
|
|
|
print("\nB. region sedang (alpha<=0.25, beta>=0.70):")
|
|
MID = [(1e-10, 1e-4), (0.001, 0.25), (0.70, 0.98), (2.1, 30.0)]
|
|
fit(rr, X0, MID, "sedang, data penuh")
|
|
fit(rr, X0, MID, "sedang, winsor=0.01", winsor=0.01)
|
|
|
|
# evaluasi standardisasi: z = r/sigma; cek std(z) & HMM sederhana
|
|
print("\nC. evaluasi z (harus std ~1, non-konstan) utk solusi terbaik di atas:")
|
|
for tag, par, wl in [
|
|
("klasik winsor=0.005", fit(rr, X0, CLS, "eval", winsor=0.005), 0.005),
|
|
]:
|
|
w, a, b, nu = par
|
|
d = np.clip(rr, -wl, wl)
|
|
s2 = np.empty(n)
|
|
s2[0] = w / (1 - a - b)
|
|
for i in range(1, n):
|
|
s2[i] = w + a * d[i - 1] ** 2 + b * s2[i - 1]
|
|
sig = np.sqrt(np.maximum(s2, 1e-12))
|
|
zz = rr / sig
|
|
print(f" z: std={zz.std():.3f} mean={zz.mean():+.4f} |z|max={np.abs(zz).max():.2f} "
|
|
f"q99={np.quantile(np.abs(zz), 0.99):.2f}")
|