Files
crpto_predictor/train_dlinear_real.py
T
crypto_predictorandClaude Sonnet 4.5 9bbdc8d42b Initial commit: BTC 1h prediction model (53.10% accuracy)
🎯 项目成果:
- 准确率: 53.10% (2026年测试集)
- 任务类型: 二分类 (预测涨/跌)
- 特征: OHLCV + RSI + MACD (9个特征)
- 训练数据: 2020-2025年BTC小时数据 (52,351序列)
- 测试数据: 2026年1-29日 (484序列)

📊 性能指标:
- 精确率: 51.79%
- 召回率: 49.36%
- F1分数: 0.5054
- 预测分布: 非常平衡 (偏差仅-11个)

🔬 实验历史:
- 尝试了5种方案 (回归/分类, 不同数据划分)
- 分类任务优于回归任务 (53.10% vs 49.5%)
- 全量训练避免了过拟合问题

📦 主要模型文件:
- models/checkpoints/dlinear_classification_2026/
  - best_model.pt (最佳模型)
  - preprocessor.pkl (预处理器)
  - test_2026_results.json (测试结果)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-29 21:27:15 +08:00

164 lines
5.7 KiB
Python

"""使用真实Binance数据训练DLinear模型"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from data.fetcher import BinanceDataFetcher
from data.preprocessor import CryptoPreprocessor, split_data
from data.dataset import create_dataloaders
from models.dlinear.model import DLinear, DLinearConfig
from training.trainer import Trainer
from training.config import TrainingConfig
import json
def main():
print("="*80)
print("DLinear模型训练 - 真实Binance数据")
print("="*80)
# 步骤1: 获取真实数据
print("\n[1/7] 从Binance获取BTC 1h真实数据...")
fetcher = BinanceDataFetcher()
df = fetcher.fetch_ohlcv('BTC', '1h', use_cache=True)
print(f"✓ 已获取 {len(df)} 行真实数据")
print(f"✓ 时间范围:{df['timestamp'].min()} 至 {df['timestamp'].max()}")
# 步骤2: 数据预处理
print("\n[2/7] 数据预处理(技术指标 + 特征工程)...")
preprocessor = CryptoPreprocessor(lookback=168, forecast_horizon=24)
X, y, processed_df = preprocessor.preprocess_pipeline(df, task='classification', fit=True)
print(f"✓ 已创建序列:X形状 = {X.shape}, y形状 = {y.shape}")
print(f"✓ 特征数量:{X.shape[-1]}")
print(f"✓ 标签分布:下跌(0) = {(y==0).sum()}, 上涨(1) = {(y==1).sum()}")
# 步骤3: 划分数据集
print("\n[3/7] 划分训练/验证/测试集 (70/15/15)...")
train_data, val_data, test_data = split_data(X, y, train_split=0.7, val_split=0.15)
# 步骤4: 创建数据加载器
print("\n[4/7] 创建PyTorch数据加载器...")
train_loader, val_loader, test_loader = create_dataloaders(
train_data, val_data, test_data,
task='classification',
batch_size=64
)
print(f"✓ 训练批次:{len(train_loader)}")
print(f"✓ 验证批次:{len(val_loader)}")
print(f"✓ 测试批次:{len(test_loader)}")
# 步骤5: 创建模型
print("\n[5/7] 创建DLinear模型...")
model_config = DLinearConfig(
input_dim=X.shape[-1],
lookback=168,
task='classification',
hidden_dim=512,
dropout=0.1,
moving_avg_kernel=25
)
model = DLinear(model_config)
print(f"✓ 模型已创建,可训练参数:{model.count_parameters():,} 个")
# 步骤6: 训练模型
print("\n[6/7] 开始训练模型...")
train_config = TrainingConfig(
batch_size=64,
max_epochs=50,
learning_rate=0.001,
early_stopping_patience=10,
lr_scheduler='plateau',
save_best=True,
checkpoint_dir='./models/checkpoints/dlinear_btc_1h_real'
)
trainer = Trainer(model, train_config, task='classification')
history = trainer.fit(train_loader, val_loader)
# 步骤7: 评估模型
print("\n[7/7] 在测试集上评估模型...")
metrics = trainer.evaluate(test_loader)
# 保存评估结果
results_path = './models/checkpoints/dlinear_btc_1h_real/test_metrics.json'
with open(results_path, 'w') as f:
json.dump(metrics, f, indent=2)
print(f"\n✓ 评估结果已保存至:{results_path}")
# 打印结果摘要
print("\n" + "="*80)
print("训练完成 - 最终测试结果")
print("="*80)
print(f"\n分类指标:")
print(f" 准确率: {metrics.get('accuracy', 0):.4f}")
print(f" F1分数: {metrics.get('f1', 0):.4f}")
print(f" 精确率: {metrics.get('precision', 0):.4f}")
print(f" 召回率: {metrics.get('recall', 0):.4f}")
if 'true_positives' in metrics:
print(f"\n混淆矩阵:")
print(f" 真阳性: {metrics['true_positives']}")
print(f" 真阴性: {metrics['true_negatives']}")
print(f" 假阳性: {metrics['false_positives']}")
print(f" 假阴性: {metrics['false_negatives']}")
print(f"\n回测结果:")
print(f" 总收益率: {metrics.get('backtest_total_return', 0)*100:.2f}%")
print(f" 最终资金: ${metrics.get('backtest_final_capital', 0):,.2f}")
print(f" 夏普比率: {metrics.get('backtest_sharpe_ratio', 0):.4f}")
print(f" 最大回撤: {metrics.get('backtest_max_drawdown', 0)*100:.2f}%")
print(f" 胜率: {metrics.get('backtest_win_rate', 0)*100:.2f}%")
print(f" 交易次数: {metrics.get('backtest_num_trades', 0)}")
# ONNX导出测试
print("\n" + "="*80)
print("测试ONNX导出")
print("="*80)
try:
import onnx
import onnxruntime as ort
import torch
import numpy as np
onnx_path = './models/checkpoints/dlinear_btc_1h_real/model.onnx'
print("\n[1/3] 导出模型到ONNX格式...")
model.to_onnx(onnx_path)
print(f"✓ ONNX模型已保存至:{onnx_path}")
print("\n[2/3] 验证ONNX模型...")
onnx_model = onnx.load(onnx_path)
onnx.checker.check_model(onnx_model)
print("✓ ONNX模型有效")
print("\n[3/3] 测试ONNX推理与PyTorch对比...")
test_input = torch.randn(1, 168, X.shape[-1])
model.cpu()
model.eval()
with torch.no_grad():
pytorch_output = model(test_input).numpy()
ort_session = ort.InferenceSession(onnx_path)
onnx_output = ort_session.run(None, {'input': test_input.numpy()})[0]
diff = np.abs(pytorch_output - onnx_output).max()
print(f"✓ PyTorch与ONNX的最大差异:{diff:.8f}")
if diff < 1e-5:
print("✓ ONNX导出成功!输出在容差范围内匹配。")
else:
print("⚠ 警告:ONNX输出与PyTorch有差异")
except Exception as e:
print(f"✗ ONNX导出失败:{e}")
print("\n" + "="*80)
print("✓ DLinear模型训练完成(真实数据)")
print("="*80)
if __name__ == "__main__":
main()