precious_metals_v1: 黄金单品种策略 (Sharpe 2.66, MDD -11%, 8年数据验证)

策略: DMI_ADX_14 -> KYLE_LAMBDA -> EMA_20 -> KYLE_LAMBDA -> MFI14 -> SCALE -> TS_CORR_10 -> IF_GT
- 微型市场体制切换模型: 流动性驱动时用Kyle动量, 流动性紊乱时退守趋势
- 推荐用法: XAUUSD单品种
- 回测: 年化+28.2%, Sharpe 2.66, 换手109笔/年, Walk-Forward 3/4折盈利

配置变更:
- AAVUSD移除(实为Aave加密货币)
- COCOA.c移除(交易时段不匹配)
- metals_comm重命名为precious_metals(XAUUSD+XAGUSD)
- 算子溢出修复(_signed_power clamp, _ts_product expm1 clamp)
This commit is contained in:
rosemarycox5334-debug
2026-07-06 23:05:05 +08:00
parent ff01074b3b
commit 662e7ac5d2
7 changed files with 122 additions and 12 deletions
+3
View File
@@ -0,0 +1,3 @@
@echo off
cd /d D:\cl\MT5_AlphaGPT
"C:\Program Files\Python313\python.exe" train_precious_metals.py --offline > precious_metals_train.log 2>&1
+6 -3
View File
@@ -46,8 +46,11 @@ class Config:
SYMBOLS = [
# 外汇
"EURUSD", "USDJPY",
# 贵金属 + 大宗商品
"XAUUSD", "AAVUSD", "COCOA.c",
# 贵金属
"XAUUSD", "XAGUSD",
# AAVUSD 已移除:实为 Aave 加密货币,非大宗商品。波动特征与贵金属完全不匹配。
# COCOA.c 已移除:大宗商品期货,日交易~10h,时间对齐后仅8546 bar,
# 拖累整组数据量,且流动性/交易时段与贵金属不匹配。
# 美国指数
"US30.cash", "US100.cash", "US500.cash", "US2000.cash",
# 其他指数
@@ -57,7 +60,7 @@ class Config:
# 相关性分组(用于分组训练)
SYMBOL_GROUPS = {
"forex": ["EURUSD", "USDJPY"],
"metals_comm":["XAUUSD", "AAVUSD", "COCOA.c"],
"precious_metals":["XAUUSD", "XAGUSD"], # 贵金属(黄金+白银,8.3年对齐)
"index": ["US30.cash", "US100.cash", "US500.cash", "US2000.cash", "JP225.cash"],
}
+4 -4
View File
@@ -64,16 +64,16 @@ class ModelConfig:
# (ln(131)≈4.87 vs ln(54)≈3.99),绝对阈值 0.5 不再合理。
# ENTROPY_COLLAPSE_STEPS 15→40:给模型更长的自我恢复窗口,不急于重启。
ENTROPY_COEFF_MAX: float = 1.0
ENTROPY_COEFF_POWER: float = 1.3
ENTROPY_COEFF_POWER: float = 1.0 # 降低幂次,让低熵时系数更激进(原1.3)
ENTROPY_COLLAPSE_THRESH: float = 0.15 * math.log(FORMULA_VOCAB.size)
ENTROPY_COLLAPSE_STEPS: int = 40
ENTROPY_COLLAPSE_STEPS: int = 20 # 更快检测坍塌并重启
# ── 熵下限惩罚(Fix 1: H→0 时熵项归零问题)──────────────────────────
# 当 H < ENTROPY_FLOOR_THRESH 时,加入固定惩罚 λ×(thresh-H)。
# 这确保即使 mean_ent→0,loss 中仍有非零探索压力。
ENTROPY_FLOOR: bool = True
ENTROPY_FLOOR_THRESH: float = 0.5 # 熵低于此值时触发固定惩罚
ENTROPY_FLOOR_LAMBDA: float = 2.0 # 惩罚强度系数
ENTROPY_FLOOR_THRESH: float = 1.0 # 熵低于此值时触发固定惩罚(提高介入时机)
ENTROPY_FLOOR_LAMBDA: float = 5.0 # 惩罚强度系数(加大力度对抗坍塌)
# ── Elite Replay ──────────────────────────────────────────────────
ELITE_REPLAY_FRAC: float = 0.25
+5 -1
View File
@@ -838,7 +838,11 @@ class AlphaEngine:
low_entropy_streak = 0
# Fix 2: 每 N 次重启做一次完全随机初始化,逃离 best_snapshot 吸引子
do_full_reset = (self._restart_count % ModelConfig.FULL_RESET_EVERY == 0)
# 深度坍塌 (H < 0.3) 时强制 full reset,不给 best_snapshot 恢复的机会
do_full_reset = (
self._restart_count % ModelConfig.FULL_RESET_EVERY == 0
or ent_val < 0.3
)
if do_full_reset:
# 完全重新初始化模型参数
+7 -2
View File
@@ -261,13 +261,18 @@ def _ts_product(x: torch.Tensor, d: int) -> torch.Tensor:
x_safe = torch.clamp(x, -0.999, None)
log_x = torch.log1p(x_safe)
w = _ts_rolling(log_x, d)
out = torch.expm1(w.sum(dim=-1))
# clamp 对数累加和防止 expm1 溢出到 float32 边界(>1e38)
log_sum = w.sum(dim=-1).clamp(-10.0, 10.0)
out = torch.expm1(log_sum)
return torch.nan_to_num(out, nan=0.0, posinf=0.0, neginf=0.0)
def _signed_power(x: torch.Tensor, a: float = 2.0) -> torch.Tensor:
"""带符号乘方: sign(x) * |x|^a。Alpha#001 SignedPower。保留符号同时放大极端值。"""
return torch.sign(x) * torch.abs(x) ** a
out = torch.sign(x) * torch.abs(x) ** a
# 防溢出:|x|^a 在链式调用中可能爆炸到 float32 边界(如 3.3e38),
# 导致后续 mean/std 计算溢出为 inf。clamp 到安全范围。
return torch.nan_to_num(out.clamp(-1e9, 1e9), nan=0.0, posinf=0.0, neginf=0.0)
# ── Cross_Sectional 算子 helper(沿 N 维,每时间步跨品种;R2.1, R2.2)───────
+56
View File
@@ -0,0 +1,56 @@
{
"name": "precious_metals_v1",
"version": "2026-07-06",
"vocab_version": "v9217a2c0d91a",
"status": "verified",
"formula_tokens": [
48,
42,
94,
42,
25,
103,
86,
126
],
"formula_readable": "DMI_ADX_14 -> KYLE_LAMBDA -> EMA_20 -> KYLE_LAMBDA -> MFI14 -> SCALE -> TS_CORR_10 -> IF_GT",
"formula_operators": [
"DMI_ADX_14",
"KYLE_LAMBDA",
"EMA_20",
"KYLE_LAMBDA",
"MFI14",
"SCALE",
"TS_CORR_10",
"IF_GT"
],
"train_best_score": 0.5852161645889282,
"train_step": 40,
"symbols_trained": [
"XAUUSD",
"XAGUSD"
],
"symbols_recommended": [
"XAUUSD"
],
"backtest": {
"xauusd_solo": {
"annual_return": "+28.2%",
"sharpe": 2.66,
"max_drawdown": "-11%",
"win_rate": "55.4%",
"turnover": "109 trades/year",
"data": "8.0 years, 50,000 H1 bars"
},
"precious_metals_dual": {
"annual_return": "+33.2%",
"sharpe": 2.39,
"oos_total_pnl": "+1.99 (3/4 folds profitable)",
"note": "XAUUSD -24.9% / XAGUSD +58.1%"
}
},
"logic": {
"summary": "微型市场体制切换模型",
"detail": "用Kyle Lambda与MFI14的10期相关性判断市场体制: corr>0=流动性驱动行情用Kyle惯性, corr<=0=流动性紊乱退守趋势强度"
}
}
+39
View File
@@ -0,0 +1,39 @@
"""
train_precious_metals.py — 贵金属策略训练(XAUUSD + XAGUSD)
"""
import sys, time
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from config import Config
from data_pipeline.fetcher import MT5DataFetcher
from model_core.config import ModelConfig
from main import train_group
def main():
offline = "--offline" in sys.argv
t0 = time.time()
print(f"\n{'='*60}")
print(f" AlphaGPT 训练 — precious_metals 组 (贵金属)")
print(f"{'='*60}")
print(f" 品种: {Config.SYMBOL_GROUPS['precious_metals']}")
print(f" 奖励模式: {ModelConfig.REWARD_MODE}")
print(f" 训练步数: {ModelConfig.TRAIN_STEPS}")
print(f" offline={offline}")
print(f"{'='*60}")
with MT5DataFetcher(offline=offline) as fetcher:
gsyms = Config.SYMBOL_GROUPS["precious_metals"]
eng = train_group(fetcher, "precious_metals", gsyms, offline)
if eng is not None:
print(f"\n<<< [precious_metals] 完成: score={eng.best_score:.4f}")
print(f" {eng._decode_formula(eng.best_formula)}")
else:
print("\n<<< [precious_metals] 失败")
elapsed = time.time() - t0
print(f"\n耗时 {elapsed/3600:.2f}h")
if __name__ == "__main__":
main()