mirror of
https://github.com/silencesdg/mt5_python_ea_suite.git
synced 2026-07-28 19:27:43 +00:00
151 lines
6.2 KiB
Python
151 lines
6.2 KiB
Python
|
|
import pandas as pd
|
|
import numpy as np
|
|
import os
|
|
import json
|
|
from datetime import datetime
|
|
|
|
# --- 本地模块导入 ---
|
|
# 导入波浪理论策略以使用其指标计算和状态判断逻辑
|
|
from strategies.wave_theory import WaveTheoryStrategy
|
|
|
|
# 导入机器学习优化器的核心函数
|
|
# (注意:我们可能需要对optimizer_ml.py稍作修改,使其核心功能可以被调用)
|
|
from optimizer_ml import run_optimizer as run_ml_optimizer, load_historical_data
|
|
|
|
# --- 配置 ---
|
|
DATA_FILE = "full_historical_data.parquet"
|
|
CLASSIFIED_DATA_FILE = "full_historical_data_classified.parquet"
|
|
RESULTS_FILE = "regime_optimal_params.json"
|
|
|
|
# --- 核心功能 ---
|
|
|
|
def classify_market_regimes(df):
|
|
"""
|
|
使用WaveTheoryStrategy中的逻辑为整个数据集打上市场状态标签。
|
|
返回一个带有 'regime' 列的 DataFrame。
|
|
"""
|
|
print("--- 开始为数据集分类市场状态 ---")
|
|
|
|
# 使用默认参数实例化策略,我们只借用它的指标计算能力
|
|
# 这里的参数值不影响状态判断的逻辑本身
|
|
strategy = WaveTheoryStrategy(data_provider=None, symbol="XAUUSD", timeframe=None)
|
|
|
|
# 1. 计算所有需要的指标
|
|
# 我们需要确保传入一个副本,避免修改原始df
|
|
df_with_indicators = strategy._calculate_indicators(df.copy())
|
|
|
|
# 2. 逐行判断市场状态
|
|
regimes = []
|
|
# 使用.values可以稍微加速循环
|
|
adx_values = df_with_indicators['adx'].values
|
|
ema_short_values = df_with_indicators['ema_short'].values
|
|
ema_medium_values = df_with_indicators['ema_medium'].values
|
|
ema_long_values = df_with_indicators['ema_long'].values
|
|
|
|
# 从实例中获取阈值
|
|
adx_threshold = strategy.adx_threshold
|
|
|
|
for i in range(len(df_with_indicators)):
|
|
# 处理NaN值的情况,在数据初期指标未生成时,设为None
|
|
if np.isnan(adx_values[i]) or np.isnan(ema_short_values[i]) or np.isnan(ema_medium_values[i]) or np.isnan(ema_long_values[i]):
|
|
regimes.append(None)
|
|
continue
|
|
|
|
# 判断震荡
|
|
# 注意:原始逻辑中还有一个range_pct的判断,这里为简化,暂时只用ADX和均线,后续可完善
|
|
if adx_values[i] < adx_threshold:
|
|
regimes.append("Ranging")
|
|
# 判断上涨趋势
|
|
elif ema_short_values[i] > ema_medium_values[i] > ema_long_values[i]:
|
|
regimes.append("Uptrend")
|
|
# 其他情况视为下跌趋势
|
|
else:
|
|
regimes.append("Downtrend")
|
|
|
|
df_with_indicators['regime'] = regimes
|
|
|
|
# 打印各类别的统计信息
|
|
print("\n市场状态分类统计:")
|
|
print(df_with_indicators['regime'].value_counts())
|
|
|
|
# 删除那些没有成功分类的行
|
|
df_with_indicators.dropna(subset=['regime'], inplace=True)
|
|
print(f"\n去除无法分类的初期数据后,剩余总行数: {len(df_with_indicators)}")
|
|
|
|
return df_with_indicators
|
|
|
|
def run_regime_based_optimization():
|
|
"""
|
|
主函数:加载数据,分类状态,并为每个状态分别运行优化器。
|
|
"""
|
|
# 1. 加载或生成带有市场状态标签的数据
|
|
if os.path.exists(CLASSIFIED_DATA_FILE):
|
|
print(f"正在从已分类的数据文件 {CLASSIFIED_DATA_FILE} 加载...")
|
|
df_classified = pd.read_parquet(CLASSIFIED_DATA_FILE)
|
|
print(f"已分类数据加载完成,共 {len(df_classified)} 条记录。")
|
|
else:
|
|
print(f"未找到已分类的数据文件,将执行初次分类...")
|
|
if not os.path.exists(DATA_FILE):
|
|
print(f"错误: 原始数据文件 {DATA_FILE} 不存在。请先运行 data_downloader.py。")
|
|
return
|
|
|
|
print(f"正在从 {DATA_FILE} 加载原始数据...")
|
|
full_df = pd.read_parquet(DATA_FILE)
|
|
print(f"原始数据加载完成,共 {len(full_df)} 条记录。")
|
|
|
|
# 为整个数据集打上状态标签
|
|
df_classified = classify_market_regimes(full_df)
|
|
|
|
# 保存已分类的数据以备将来使用
|
|
print(f"正在将分类后的数据保存到 {CLASSIFIED_DATA_FILE}...")
|
|
try:
|
|
df_classified.to_parquet(CLASSIFIED_DATA_FILE)
|
|
print("保存完成。")
|
|
except Exception as e:
|
|
print(f"保存已分类数据时出错: {e}")
|
|
|
|
# 3. 按状态分组,并分别进行优化
|
|
all_regime_params = {}
|
|
regimes_to_optimize = ['Uptrend', 'Downtrend', 'Ranging']
|
|
|
|
for regime in regimes_to_optimize:
|
|
print(f"\n{'='*80}\n--- 开始为【{regime}】市场状态进行参数优化 ---\n{'='*80}")
|
|
|
|
regime_df = df_classified[df_classified['regime'] == regime].copy()
|
|
|
|
if len(regime_df) < 5000: # 如果某个状态的数据太少,优化可能无意义
|
|
print(f"警告: {regime} 状态的数据量过少 ({len(regime_df)}条),跳过优化。")
|
|
continue
|
|
|
|
# 调用ML优化器,并把特定状态的数据传递给它
|
|
# *** 注意:这需要我们修改 optimizer_ml.py 中的 run_optimizer 函数,使其能接收一个DataFrame作为参数 ***
|
|
# *** 目前,我们先假设这个修改已经完成 ***
|
|
try:
|
|
best_params, best_sharpe = run_ml_optimizer(regime_df)
|
|
all_regime_params[regime] = {
|
|
'best_sharpe': best_sharpe,
|
|
'best_parameters': best_params
|
|
}
|
|
print(f"\n---【{regime}】状态优化完成!最佳夏普比率: {best_sharpe:.4f} ---")
|
|
except Exception as e:
|
|
print(f"为 {regime} 状态优化时发生严重错误: {e}")
|
|
import traceback
|
|
print(traceback.format_exc())
|
|
|
|
# 4. 保存最终结果
|
|
if all_regime_params:
|
|
print(f"\n{'='*80}\n--- 所有市场状态优化全部完成!---\n{'='*80}")
|
|
print("最终结果:")
|
|
print(json.dumps(all_regime_params, indent=2))
|
|
|
|
with open(RESULTS_FILE, 'w', encoding='utf-8') as f:
|
|
json.dump(all_regime_params, f, ensure_ascii=False, indent=4)
|
|
|
|
print(f"\n结果已保存到: {os.path.abspath(RESULTS_FILE)}")
|
|
else:
|
|
print("\n没有完成任何状态的优化。")
|
|
|
|
if __name__ == "__main__":
|
|
run_regime_based_optimization()
|