Files
AlphaMaster/train_single.py
T
2026-07-10 18:14:59 +08:00

157 lines
5.0 KiB
Python

"""
train_single.py — 单品种训练入口
用法:
python train_single.py XAUUSD [--offline]
每个品种独立训练,checkpoint: checkpoints/ckpt_{symbol}_step_{N}.pt
训练完成后保存策略: strategies/best_{symbol}.json
"""
import sys, time, pathlib
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from config import Config
from data_pipeline.fetcher import MT5DataFetcher
from data_pipeline.data_manager import MT5DataManager
from model_core.config import ModelConfig
from model_core.engine import AlphaEngine
def train_single(fetcher, symbol: str, offline: bool):
"""训练单个品种。
自动检测 checkpoint 续训,完成后保存策略到 strategies/best_{symbol}.json。
"""
import json, glob as _g
print(f"\n{'='*60}")
print(f" AlphaGPT 单品种训练 — {symbol}")
print(f"{'='*60}")
print(f" 奖励模式: {ModelConfig.REWARD_MODE}")
print(f" 训练步数: {ModelConfig.TRAIN_STEPS}")
print(f" K线目录: {Config.KLINE_CACHE_DIR}")
print(f" 离线模式: 是(仅读本地缓存)")
print(f"{'='*60}")
# 加载全部品种数据,然后切出单品种视图
original = Config.SYMBOLS[:]
Config.SYMBOLS = [symbol]
try:
mgr = MT5DataManager(fetcher)
mgr.load()
T = mgr.raw_dict["open"].shape[1]
print(f" 数据: {symbol} T={T} bars ({T/6240:.2f}年)")
except Exception as e:
print(f" [错误] 数据加载失败: {e}")
Config.SYMBOLS = original
return None
finally:
Config.SYMBOLS = original
engine = AlphaEngine(data_manager=mgr, target_symbol=symbol)
# 自动续训
ckpt_pattern = str(pathlib.Path("checkpoints") / f"ckpt_{symbol}_step_*.pt")
ckpt_files = sorted(_g.glob(ckpt_pattern))
start_step = 0
if ckpt_files:
latest = ckpt_files[-1]
try:
engine.load_checkpoint(latest)
start_step = engine._step if hasattr(engine, '_step') else int(
latest.split('_step_')[-1].replace('.pt', '')
)
print(f" [续训] 从 {latest} 恢复,start_step={start_step}")
except Exception as e:
print(f" [警告] checkpoint 加载失败: {e},将从头开始")
if start_step >= ModelConfig.TRAIN_STEPS:
print(f" [完成] {symbol} 已完成全部 {ModelConfig.TRAIN_STEPS} 步,跳过训练")
_save_strategy(engine, symbol)
return engine
if start_step == 0:
print(f" [新训] 从 step 0 开始")
engine.train(start_step=start_step)
_save_strategy(engine, symbol)
return engine
def _save_strategy(engine, symbol):
"""保存单品种策略"""
import json
from model_core.vocab import VOCAB_VERSION
pathlib.Path("strategies").mkdir(exist_ok=True)
path = pathlib.Path("strategies") / f"best_{symbol}.json"
data = {
"vocab_version": VOCAB_VERSION,
"symbol": symbol,
"mode": "single",
"formula": engine.best_formula,
"formula_decoded": engine._decode_formula(engine.best_formula)
if engine.best_formula else None,
"best_score": engine.best_score,
"train_steps": ModelConfig.TRAIN_STEPS,
}
with open(path, "w") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f" 策略已保存: {path}")
# ── CLI ────────────────────────────────────────────────────────
if __name__ == "__main__":
offline = True
mode = "ftmo"
syms: list[str] = []
skip_next = False
for arg in sys.argv[1:]:
if skip_next:
skip_next = False
continue
if arg == "--mode":
skip_next = True
continue
if arg == "--cache-dir":
skip_next = True
continue
if arg.startswith("--"):
continue
syms.append(arg)
if "--mode" in sys.argv:
idx = sys.argv.index("--mode")
mode = sys.argv[idx + 1] if idx + 1 < len(sys.argv) else "ftmo"
if "--cache-dir" in sys.argv:
idx = sys.argv.index("--cache-dir")
if idx + 1 < len(sys.argv):
Config.KLINE_CACHE_DIR = sys.argv[idx + 1]
ModelConfig.REWARD_MODE = mode
if not syms:
print("用法: python train_single.py <SYMBOL> [--cache-dir PATH] [--mode ftmo]")
print(f"可选品种: {Config.TRAINABLE_SYMBOLS}")
sys.exit(1)
symbol = syms[0]
if symbol not in Config.TRAINABLE_SYMBOLS:
print(f"警告: {symbol} 不在 TRAINABLE_SYMBOLS 列表中,但仍将尝试训练")
t0 = time.time()
with MT5DataFetcher(offline=offline) as fetcher:
eng = train_single(fetcher, symbol, offline)
elapsed = time.time() - t0
if eng:
print(f"\n<<< [{symbol}] 完成: score={eng.best_score:.4f} 耗时 {elapsed/3600:.2f}h")
if eng.best_formula:
print(f" {eng._decode_formula(eng.best_formula)}")
else:
print(f"\n<<< [{symbol}] 失败")