feat: 适应度门槛95+swing_point策略+多项改进

- 新增适应度门槛: min_backtest_fitness=95, 适应度<95暂停开仓
- 新增 SwingPointRetest 策略替代 Turtle
- 新增 monday_reset.py 周重置脚本
- exit_rules: 拖尾止损相对回撤模式
- market_state: 趋势检测优化
- position: 一票制并发锁+合约规格缓存
- optimize: Optuna 替代 DEAP 遗传算法
- realtime_trader: 适应度门槛+同向递增
- weights: 动态权重管理
- cron_optimize: PYTHONPATH 修复
- .gitignore: 排除生成文件
This commit is contained in:
silencesdg
2026-05-21 20:26:55 +08:00
parent 218efef538
commit e1691c3c41
14 changed files with 699 additions and 449 deletions
+39 -23
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""每日自动优化 — 遗传算法跑参数 → 写入config → 重启实盘EA
"""每日自动优化 — 遗传算法跑参数 → 写入config → EA热加载生效(无需重启)
通过 cron 调用: python3 scripts/daily_optimize.py
"""
@@ -22,12 +22,12 @@ RESTART_SIGNAL = PROJECT_DIR / ".restart_signal"
def run_optimizer():
"""运行遗传算法优化,返回 best_params dict"""
"""运行遗传算法优化,返回 (best_params dict, fitness)"""
from execution.optimize import run_optimizer as _run
logger.info("🧬 开始遗传算法优化...")
best_params, fitness = _run()
logger.info(f"✅ 优化完成 适应度={fitness:.2f}")
return best_params
return best_params, fitness
def backup_config():
@@ -39,18 +39,13 @@ def backup_config():
logger.info(f"📦 已备份配置: {dst}")
def update_config(best_params: dict):
def update_config(best_params: dict, fitness: float = 0.0):
"""将优化结果写回 config.py"""
content = CONFIG_PATH.read_text(encoding="utf-8")
# ═══ RISK_CONFIG ═══
# ═══ RISK_CONFIG — 手动设定,不进优化器 ═══
# optimizer.py PARAM_SPACE 已移除风控基因,此 map 清空)
risk_map = {
"stop_loss_pct": "stop_loss_pct",
"profit_retracement_pct": "profit_retracement_pct",
"min_profit_for_trailing": "min_profit_for_trailing",
"take_profit_pct": "take_profit_pct",
"max_holding_minutes": "max_holding_minutes",
"min_profit_for_time_exit": "min_profit_for_time_exit",
}
for opt_key, cfg_key in risk_map.items():
if opt_key in best_params:
@@ -115,8 +110,11 @@ def update_config(best_params: dict):
"momentum_breakout_momentum_period": ("momentum_breakout", "momentum_period"),
# KDJStrategy
"kdj_period": ("kdj", "period"),
# TurtleStrategy
"turtle_period": ("turtle", "period"),
# SwingPointRetestStrategy
"swing_point_left_bars": ("swing_point", "left_bars"),
"swing_point_right_bars": ("swing_point", "right_bars"),
"swing_point_tolerance_pct": ("swing_point", "tolerance_pct"),
"swing_point_num_swings": ("swing_point", "num_swings"),
# DailyBreakoutStrategy
"daily_breakout_bars_count": ("daily_breakout", "bars_count"),
# WaveTheoryStrategy
@@ -151,7 +149,7 @@ def update_config(best_params: dict):
"weight_MomentumBreakoutStrategy": "momentum_breakout",
"weight_MACDStrategy": "macd",
"weight_KDJStrategy": "kdj",
"weight_TurtleStrategy": "turtle",
"weight_SwingPointRetestStrategy": "swing_point",
"weight_DailyBreakoutStrategy": "daily_breakout",
"weight_WaveTheoryStrategy": "wave_theory",
}
@@ -213,6 +211,13 @@ def update_config(best_params: dict):
content
)
# ═══ LAST_OPTIMIZATION_FITNESS ═══
content = re.sub(
r'LAST_OPTIMIZATION_FITNESS\s*=\s*[\d.\-e]+',
f'LAST_OPTIMIZATION_FITNESS = {fitness:.2f}',
content
)
CONFIG_PATH.write_text(content, encoding="utf-8")
logger.info("✏️ 配置已更新")
@@ -222,11 +227,24 @@ def restart_ea():
import subprocess
logger.info("🔄 重启 EA...")
# 杀旧进程
# 杀旧进程,等锁释放再启动新的
subprocess.run(["pkill", "-f", "python.*run/realtime.py"], capture_output=True)
import time; time.sleep(2)
subprocess.run(["pkill", "-9", "-f", "python.*run/realtime.py"], capture_output=True)
time.sleep(1)
# 确认旧进程已死 + 锁已释放(轮询最多等 5 秒)
lock_file = PROJECT_DIR / ".ea.lock"
import fcntl as _fcntl
for _ in range(10):
time.sleep(0.5)
try:
fd = os.open(str(lock_file), os.O_RDONLY)
_fcntl.flock(fd, _fcntl.LOCK_EX | _fcntl.LOCK_NB)
os.close(fd) # 立即释放,只是测试
break
except (BlockingIOError, OSError):
pass
else:
logger.warning("⚠️ 旧进程锁未释放,强制启动(旧进程可能僵死)")
# 清空旧交易记录
for f in PROJECT_DIR.glob("realtime_trades_*"):
@@ -259,20 +277,18 @@ def main():
# 2. 运行优化
try:
best_params = run_optimizer()
best_params, fitness = run_optimizer()
except Exception as e:
logger.error(f"优化失败: {e}")
import traceback
traceback.print_exc()
return 1
# 3. 写入 config.py
update_config(best_params)
# 3. 写入 config.py(含适应度)
update_config(best_params, fitness)
# 4. 触发重启
restart_ea()
logger.info("✅ 每日优化流程完成")
# 4. ★ EA 通过 config.reload() 自动热加载,无需重启
logger.info("✅ 每日优化流程完成 (EA 将在下个周期自动读取新配置)")
return 0