From 016ada6512b9eee5d927e2851a298abac4076ddd Mon Sep 17 00:00:00 2001 From: xxm Date: Sun, 16 Aug 2026 12:56:40 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20evolution=5Fengine=E6=8E=A5=E5=85=A5?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BD=92=E7=BA=B3=E5=81=87=E8=AE=BE=E2=80=94?= =?UTF-8?q?=E2=80=94=E4=BC=98=E5=85=88=E5=BD=92=E7=BA=B3=E5=81=87=E8=AE=BE?= =?UTF-8?q?=E5=8F=98=E4=BD=93(=E5=8A=A0=E6=9D=A1=E4=BB=B6=E8=A7=84?= =?UTF-8?q?=E9=81=BF),=E6=97=A0=E5=81=87=E8=AE=BE=E6=89=8D=E5=9B=9E?= =?UTF-8?q?=E9=80=80=E5=8F=82=E6=95=B0=E5=8F=98=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- evolution/evolution_engine.py | 59 +++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/evolution/evolution_engine.py b/evolution/evolution_engine.py index b673f62e..bbff4152 100644 --- a/evolution/evolution_engine.py +++ b/evolution/evolution_engine.py @@ -29,6 +29,7 @@ from datetime import datetime, timedelta sys.path.insert(0, "/home/hmo/MoFin") sys.path.insert(0, "/home/hmo/MoFin/deploy/profile-scripts") +sys.path.insert(0, "/home/hmo/MoFin/evolution") DB = os.environ.get("MOFIN_DB", "/home/hmo/MoFin/data/mofin.db") WEIGHTS_JSON = "/home/hmo/MoFin/data/strategy_weights.json" @@ -172,6 +173,54 @@ def get_parent_cagr(conn, version, market, period_tag=BT_PERIOD_TAG): return None, None +def generate_hypothesis_variants(version, market, base_config, period_tag=BT_PERIOD_TAG): + """2026-08-16 数据归纳假设变体:从交易数据归纳可描述条件 → 生成加条件的策略版本 + 假设格式:{feature, direction(max/min), threshold} → 对应入场条件 + 返回 [{version, name, config, change_desc, evidence, hypothesis}] + """ + try: + from hypothesis_miner import induce_hypotheses + hs, _ = induce_hypotheses(version, market, period_tag=period_tag) + except Exception: + hs = [] + variants = [] + for h in hs[:MAX_VARIANTS_TEST]: + feat = h["feature"] + direction = h["direction"] + threshold = h["threshold"] + # 映射到策略 config 的字段(A股 entry.filters/mr,港股 entry 顶层) + cfg = copy.deepcopy(base_config) + if market == "hk": + entry = cfg.get("entry", {}) + else: + entry = cfg.get("entry", {}) + # 字段名映射:面板字段 → 策略字段(多数同名,A股 mr 下) + key = feat + target = entry + # A股 config 是 {entry:{filters,mr}} 结构,找可放的位置 + if market != "hk": + if "mr" in entry: + target = entry["mr"] + elif "filters" in entry: + target = entry["filters"] + if direction == "max": + target[key + "_max"] = threshold + else: + target[key + "_min"] = threshold + vname = f"evo_{version}_{key}_{direction}{threshold}" + variants.append({ + "version": vname, + "name": f"自进化-{version}-规避{key}{direction}{threshold}", + "config": cfg, + "change_desc": f"[数据归纳] {h['hypothesis']}", + "evidence": h.get("evidence", ""), + "hypothesis": h.get("hypothesis", ""), + "field": key, + "delta": 0, + }) + return variants + + def generate_variants(version, market, config): """生成变体参数建议:单变量 ±20%,最多 MAX_VARIANTS 个 返回 [{version, name, config, change_desc, field, delta}]""" @@ -330,7 +379,10 @@ def run_evolution(): if not base: log(f" {v} 无港股策略定义,跳过") continue - variants = generate_variants(v, mkt, base) + # 2026-08-16 优先数据归纳假设,无则参数变体 + variants = generate_hypothesis_variants(v, mkt, base) + if not variants: + variants = generate_variants(v, mkt, base) verify_fn = verify_variant_hk else: try: @@ -339,7 +391,10 @@ def run_evolution(): except ValueError: log(f" {v} 不在标准回测体系(scanner 类策略),跳过变体研究") continue - variants = generate_variants(v, mkt, base["config"]) + # 2026-08-16 优先数据归纳假设,无则参数变体 + variants = generate_hypothesis_variants(v, mkt, base["config"]) + if not variants: + variants = generate_variants(v, mkt, base["config"]) verify_fn = verify_variant_a if not variants: log(f" {v} 无可用变体字段,跳过")