Files

126 lines
4.0 KiB
Python

"""
evolution/auto_iterator.py — 策略自动迭代
健康度低时生成参数变体,跑回测,记录结果
"""
import sys, os, json, sqlite3, copy
from datetime import datetime
sys.path.insert(0, '/home/hmo/MoFin')
import strategy_lab as lab
DB = '/home/hmo/MoFin/data/mofin.db'
# 可迭代的参数空间
PARAM_SPACE = {
'max_hold_days': [40, 60, 80, 100, 120],
'reentry_days': [5, 10, 15, 20],
'sl_atr': [1.0, 1.5, 2.0, 2.5],
}
def get_current_health(version='v_next4', days=7):
"""获取当前策略健康度"""
conn = sqlite3.connect(DB)
conn.row_factory = sqlite3.Row
rows = conn.execute("""
SELECT health_score, date FROM strategy_health
WHERE strategy_version=? ORDER BY date DESC LIMIT ?
""", (version, days)).fetchall()
conn.close()
if not rows:
return 50 # 无数据,中性
return round(sum(r['health_score'] for r in rows) / len(rows), 1)
def propose_variants(parent_version, health):
"""根据健康度生成变体参数建议"""
if health >= 70:
print(f"健康度{health}≥70,无需迭代", flush=True)
return []
variants = []
severity = 'minor' if health >= 50 else 'major'
if severity == 'minor':
# 小幅调参
variants.append({
'parent': parent_version,
'params': {'max_hold_days': 80, 'reentry_days': 15, 'sl_atr': 1.5},
'description': '微调:确保当前最优参数',
})
else:
# 大幅调参(扫参数网格)
base_hold = 60
base_reentry = 10
for hold in PARAM_SPACE['max_hold_days']:
for reentry in PARAM_SPACE['reentry_days']:
variants.append({
'parent': parent_version,
'params': {'max_hold_days': hold, 'reentry_days': reentry, 'sl_atr': 1.5},
'description': f'网格扫描: h{hold}/r{reentry}',
})
return variants
def test_variant(variant):
"""测试单个变体"""
name = f"auto_h{variant['params']['max_hold_days']}_r{variant['params']['reentry_days']}"
# 克隆基座配置
base = lab.STRATEGIES.get(variant['parent'])
if not base:
return None
cfg = copy.deepcopy(base)
cfg['version'] = name
cfg['name'] = f"自进化-{variant['description']}"
for k, v in variant['params'].items():
cfg['config']['exit'][k] = v
lab.STRATEGIES[name] = cfg
results = {}
for tag, start, end in [('5y', '2021-07-01', '2026-07-24')]:
r = lab.run_backtest(name, start, end, 913000, save=False, universe='a', period_tag=tag)
pf = r['summary'].get('portfolio_full', {})
results[tag] = {
'full': pf.get('total_return_pct'),
'cagr': pf.get('cagr_pct'),
'dd': pf.get('portfolio_max_dd_pct'),
}
return {'name': name, 'description': variant['description'], 'results': results}
def run_iteration(version='v_next4'):
"""执行一次迭代检查"""
health = get_current_health(version)
print(f"{version} 健康度: {health}", flush=True)
variants = propose_variants(version, health)
if not variants:
return []
conn = sqlite3.connect(DB)
results = []
for v in variants[:3]: # 最多测3个
print(f"测试: {v['description']}", flush=True)
r = test_variant(v)
if r:
results.append(r)
# 记录到 evolution 表
conn.execute("""
INSERT INTO strategy_evolution (parent_version, child_version, change_description, backtest_result, promoted)
VALUES (?, ?, ?, ?, 0)
""", (version, r['name'], r['description'], json.dumps(r['results'], ensure_ascii=False)))
conn.commit()
# 打印对比
for r in results:
rs = r['results'].get('5y', {})
print(f" {r['name']}: full={rs.get('full')}% cagr={rs.get('cagr')}% dd={rs.get('dd')}%", flush=True)
conn.close()
return results
if __name__ == '__main__':
run_iteration()