126 lines
4.0 KiB
Python
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()
|