**文檔目標:** 將進化系統降維為一個純粹的尋優黑盒。進化引擎不關心具體策略內部結構，只通過抽象介面驅動種群生命週期。具體策略的染色體字段、邊界、適應度語義由策略模組在各自文檔中定義。

---

## 0. 核心定位

進化引擎是一個**純計算線程**：接收策略提供的基因空間與評估函數，對種群執行多代進化，交付最優基因集（Champion）。

引擎不關心：策略內部的信號公式、倉位三態語義、特定時鐘機制，也不 import 任何具體策略實現。引擎只知道：基因是一個可採樣、可變異、可交叉、可評分的抽象向量。

**輸入：** 策略提供的基因空間（邊界、約束）+ 歷史 K 線資料集 + 進化配置參數

**輸出：** 挑戰者（challenger）基因包 JSON，寫入資料庫，等待人工 Promote 為冠軍


---

## 1. 探索窗口定義

### 1.1 資料切片窗口（多時段坩堝）

Epoch 啟動時，引擎一次性從資料庫拉取**本 Epoch 所需的全部**歷史 K 線序列用於構造坩堝：**不對全庫長度設「最多十年」等人工上限**；能有多長取決於上游已同步入 Postgres 的資料，而下限以**資料源側可拉取到的最早可用 bar** 為準（例如滬深300ETF、黃金ETF 等標的能同步多早就多早，直至 API/上市歷史起點）。在此基礎上再構造以下四個滾動窗口（標識「10y」表示長週期檔，**評分區間取入庫全序列**——自最早可用 bar 至最新 bar，不設人工天數上限）。

| 窗口標識 | 目標時長（評分截取區間） | 適應度權重 |
|---------|---------|---------|
| 10y | 全量（最早至最新 bar） | 0.40 |
| 5y | 1825 天 | 0.30 |
| 2y | 730 天 | 0.20 |
| 6m | 183 天 | 0.10 |

表中「目標時長」：5y / 2y / 6m 為對齊最新一根 bar 的最近若干日曆日，並在該截取區間之前再預留最多 1200 天 warmup K 線（用於指標預熱，不計入評分區間）。**10y 檔不再單獨截斷為固定天數**，直接使用本 Epoch 傳入的 `bars` 全序列；若序列長於十年，則長週期評分自然覆蓋更長曆史。更短窗口仍使用同一全庫序列中的尾部片段及各自 warm-up 前綴。

**嚴禁未來資料洩露：** 每個窗口的評估區間從 `EvalStartMs` 開始，warmup 資料必須在 `EvalStartMs` 之前。


### 1.2 基因空間窗口

策略通過以下語義向引擎提供基因邊界，引擎不直接讀取字段名：

- **採樣（Sample）：** 從合法空間隨機生成一個基因實例
- **修復（Clamp）：** 將越界基因修復到合法範圍（含結構約束脩復）
- **驗證（Validate）：** 檢查基因是否合法


### 1.3 出生點凍結窗口（Epoch 級）

**`quant.SpawnPoint`**（`CapitalPolicy` + `RiskBounds`）在 Epoch 啟動時固定，全種群共享；不參與代內交叉變異，不進入基因組指紋。

當前 QuantSaaS 實現：`POST /api/v1/evolution/tasks` 支持 `spawn_mode`：`inherit`（冠軍包或預設）、`random_once`（排隊時抽樣一次並凍結）、`manual`（請求體填寫 `spawn_point`）。引擎經 `EpochConfig.SpawnPointOverride` 注入 `internal/saas/ga`（見 `handler_evolution.go`、`engine.go`）。

---

## 2. 進化生命週期動作

### 2.1 種群初始化

種群大小預設 `Population = 300`，初始化策略：

當資料庫中存在精英基因時：
- **10%**：從資料庫精英中原樣拷貝
- **40%**：在精英基礎上施加加性高斯強化變異（初始化路徑固定變異概率 `0.15`、尺度 `1.5`，與代內 `MutationRamp` 無關）
- **50%**：完全隨機生成

當資料庫無精英時：第一個體為產品預設冠軍染色體原樣，其餘個體完全隨機生成。

實現約定：索引 0 始終為當前種子冠軍原樣（有 DB 精英則為庫中冠軍染色體，否則為產品預設冠軍）；僅對索引 1 起的剩餘個體按上表約 10% / 40% / 50% 計數分配（相對剩餘個體數四捨五入）；無 DB 精英時索引 1 起全部為 `RandomChromosome`。


### 2.2 併發適應度評估

評估採用固定大小 worker pool 併發執行：

$$Workers = \min(NumCPU,\; PopulationSize)$$

每個 worker 獨佔一份 Adapter 實例（回測上下文），無共享可變狀態。所有 worker 併發處理任務隊列，等所有任務完成後進入下一代。


### 2.3 選擇（錦標賽 Tournament）

每次選擇從種群中隨機抽 `TournamentSize`（預設 3）個個體，取適應度最高者為父代。適應度為 `fatalFitnessScore`（災難性極小值）的個體在錦標賽中自然被淘汰（無需顯式排除，因 fatal 個體分數極低）。


### 2.4 交叉（Uniform Crossover）

對每個基因維度以 0.5 概率獨立地從兩個父代中選取，生成子代。引擎不關心字段語義，由策略的 `Clamp` 邏輯在交叉後修復結構約束。

當前實現：`uniformCrossoverWithMode` 對所有維度獨立 50% 交換，結構約束脩覆在交叉後調用 `repairGeneWithMode`。宏觀/微觀塊正交交叉為[規劃，未實現]。


### 2.5 變異（加性高斯）

每個基因維度以獨立 Bernoulli 概率 `MutationProbability`（預設 0.15）決定是否變異；變異量為 `NormFloat64() × GeneStep × MutationScale`（預設 Scale=1.0）。變異後調用 Clamp 修復越界值。


### 2.6 精英保留（Elitism）

每代保留適應度 Top `Elitism`（預設 8）個個體，不經交叉變異直接入下一代。


### 2.7 收斂檢測與變異斜坡（Mutation Ramp）

連續 `EarlyStopPatience`（預設 5）代內最佳適應度改善低於 `EarlyStopMinDelta`（預設 0.001）時，觸發變異斜坡：

$$MutationProbability \mathrel{\times}= MutationRampProbFactor \;(1.25)$$

$$MutationScale \mathrel{\times}= MutationRampScaleFactor \;(1.25)$$

上限：`MutationProbabilityMax = 0.55`，`MutationScaleMax = 3.0`

當變異參數觸及上限後仍無改善，才真正提前終止（Early Stop）。


### 2.8 Genome 指紋緩存（Fingerprint Cache）

策略提供 Fingerprint（指紋）語義（對基因向量按精度 1e-6 哈希），引擎在 Epoch 內檢測重複個體，命中緩存則複用評估結果，跳過重複回測。預期命中率約 15–30%（來自精英保留產生的重複）。

### 2.9 收斂交付

進化結束後（正常完成或 Early Stop），將最優基因包編碼為 JSON（`EncodeResult`），寫入資料庫為 `challenger` 角色。進化任務不自動 Promote，必須等待人工審批。


---

## 3. 適應度黑盒（Fitness Function）

### 3.1 多窗口坩堝分數

對每個切片窗口，以策略的累計回報相對於 Ghost DCA 基準計算 Alpha，再按超額回撤懲罰：

$$Alpha = ROI_{strategy} - ROI_{GhostDCA}$$

$$SliceScore = Alpha - 1.5 \times \max(0,\; MaxDD_{strategy} - MaxDD_{GhostDCA})$$

當 $MaxDD_{strategy} \geq 0.88$ 時，`SliceScore = -99999`（硬否決，fatal）。

各窗口加權彙總：

$$ScoreTotal = 0.40 \times Score_{10y} + 0.30 \times Score_{5y} + 0.20 \times Score_{2y} + 0.10 \times Score_{6m}$$


### 3.2 Ghost DCA 基準

`SimulateGhostDCA` 以種子資本買入標的資產（如滬深300ETF或黃金ETF），然後每自然月月初注入月度預算用全部可用 CNY 加倉買入，作為被動 DCA 基準。策略個體必須跑贏此基準（Alpha > 0）才算有效。

注資節奏：月度 `monthlyInject` CNY，在每個自然月邊界觸發。


### 3.3 ROI 計算

策略的 ROI 採用"Modified Dietz 收益率"思路，剔除注資跳變對 NAV 的影響（注資時刻的權益變化不計入收益）。NAV 最大回撤基於淨資產曲線計算。


### 3.4 級聯短路（Cascading Short-circuit）

適應度評估按切片窗口從短到長（6m → 2y → 5y → 10y）順序執行。一旦某個窗口觸發 fatal（MaxDD ≥ 88%），立即返回 fatal 分數，跳過後續更長的窗口。


---

## 4. 性能優化機制

以下優化已在當前實現中落地：

**4.1 級聯短路：** 按窗口長度升序評估，fatal 立即終止（見 3.4）。

**4.2 併發評估：** Genome 粒度 worker pool，CPU 數量上限（見 2.2）。

**4.3 Tournament fatal 排除：** fatal 個體因分數極低，在錦標賽中幾乎不會被選中（無需顯式過濾）。

以下優化屬於**規劃，未實現**：

**4.4 Nested Replay（嵌套重放）：** 一次全樣本回測 + 各窗口 EvalStart checkpoint 差分，將 4 次獨立回測合併為 1 次，減少 75% 計算量。[規劃，未實現] **注意：此優化與 4.1 級聯短路存在根本衝突**——Nested Replay 必須先跑完整 10y 序列才能提取子窗口結果，無法在 6m fatal 時提前退出；而早期代 fatal 率通常 40–60%，10y bar 量約為 6m 的 10 倍，實施後反而劣化約 4×。僅在 fatal 率極低（< 10%）且短路收益可忽略時才有淨收益，當前不宜實現。

**4.5 前綴和 O(1) 滑窗統計 + EMA 增量化：** 減少每次適應度評估中的重複統計計算。[規劃，未實現]

**4.6 蒙特卡洛異步化：** Epoch 驗證階段的 MC 採樣並行化，主線程等待結果。[規劃，未實現]


---

## 5. Epoch 驗證與蒙特卡洛

Epoch 進化結束後，對產出的冠軍候選執行額外驗證（屬於[規劃，未實現]，當前實現跳過此步驟）：

**5.1 全樣本複核：** 對冠軍在全樣本 1m 精度資料上重跑一次，確保 Adapter 內嵌的指標預熱不影響結果。

**5.2 蒙特卡洛風險評估：** 對冠軍的成交對數收益序列執行 `RunMonteCarlo`，輸出：
- 破產概率（Ruin Probability）
- 收益分位數（第 5、50、95 百分位的終局權益）

[規劃，未實現]

---

## 6. 結果交付與基因角色

### 6.1 基因角色三態

資料庫中的基因記錄有三種角色，形成狀態機：

| 角色 | 含義 |
|------|------|
| `challenger` | 進化產出，等待人工審批 |
| `champion` | 當前活躍冠軍，驅動實盤實例 |
| `retired` | 歷史冠軍，僅供查閱與回溯 |


### 6.2 人工 Promote 流程

進化任務產出 `challenger` 後，操作員在前端查看回測報告與風險指標，決定是否晉升。晉升操作在資料庫事務內執行：

1. 當前 `champion` 改為 `retired`
2. 選定的 `challenger` 改為 `champion`，記錄激活時間

晉升完成後，SaaS 的冠軍緩存（Redis key）立即失效，下次 cron tick 時自動加載新冠軍。


### 6.3 規劃但未實現（當前 Epoch 不含）

以下機制**規劃但未實現**，不應納入當前開發範圍：
- **WFO 推進式滾動測試（Walk-Forward Optimization）：** 按時間軸向前推進的滾動回測，防止過擬合
- **定時自動觸發 GA：** cron 定期自動啟動進化任務，無需人工觸發


---

## 7. HTTP 觸發契約（最小集合）

進化任務通過 REST API 觸發，僅在 `app_role: lab` 或 `dev` 下可用。

### 7.1 創建進化任務

參數：
- `pop_size`：種群大小，預設 300，範圍 [10, 500]
- `max_generations`：最大代數，預設 25，範圍 [5, 50]
- `spawn_mode`（可選）：`inherit` | `random_once` | `manual`；`manual` 時須帶 `spawn_point`（JSON，與 `quant.SpawnPoint` 對齊）
- `test_mode`（可選）：快速測試模式，Pop=10, Gen=3


### 7.2 查詢任務狀態與結果

返回當前進化任務狀態（是否運行中）、歷次 challenger 基因列表（含 ScoreTotal、MaxDrawdown、各窗口分數）。

---

## 8. EvolvableStrategy 抽象介面

進化引擎通過此介面與具體策略完全解耦，`engine.go` 不含任何策略特有的染色體字段名或類型引用。

### 8.1 八動詞契約

| 動詞 | 職責 |
|------|------|
| `StrategyID()` | 返回策略唯一標識符 |
| `Sample(rng)` | 從合法基因空間隨機採樣一個基因 |
| `Mutate(c, prob, scale, rng)` | 對基因施加加性高斯變異 |
| `Crossover(p1, p2, rng)` | 對兩個父代執行交叉，產出子代 |
| `Fingerprint(c)` | 返回基因的唯一哈希（FNV-1a，精度 1e-6） |
| `Evaluate(ctx, c, plan)` | 在給定坩堝計劃上評估基因，返回適應度與各窗口明細 |
| `DecodeElite(json)` | 從 DB ParamPack JSON 解碼精英基因；`null` 時返回預設種子 |
| `EncodeResult(c, spawn)` | 將冠軍基因與出生點序列化為 ParamPack JSON（`spawn_point` + `[strategy]_config`） |
| `Verify(ctx, c, spawn, bars, lotStep, lotMin)` | 驗證路徑全量回測（含 Monte Carlo），返回 `BacktestMetrics` |

`Gene = any`：引擎持有不透明載體，不讀取內部字段。

### 8.2 EvaluablePlan 只讀上下文

`EvaluablePlan` 在 Epoch 啟動時由 `buildEvaluablePlan` 構建，在整個世代內不可變，傳遞給所有 `Evaluate` 調用：

```
EvaluablePlan
├── Symbol, TemplateName         // 標的代碼與模板標識
├── Spawn *quant.SpawnPoint      // 出生點（共享）
├── LotStep, LotMin              // 下單精度
├── Windows []CrucibleWindow     // 4 個切片窗口（含 K 線與權重）
├── DCABaselines []DCABaseline   // 預計算的 ghost-DCA 基線（與 Windows 一一對應）
└── AggregateCache               // 預聚合指標緩存（可選）
```

DCA 基線在 Epoch 啟動時一次性計算，代內各染色體評估直接讀取，不重複運行 DCA 回測。

### 8.3 引擎對染色體內部字段不可見原則

`engine.go` 通過八個動詞操作 `Gene`，對染色體字段名完全不可見。新增策略（如滬深300ETF、黃金ETF 或其他自定義 A 股/黃金策略）只需實現 `EvolvableStrategy` 介面，無需修改引擎代碼。

### 8.4 包位置約束（導入循環）

`[YourStrategy]Evolvable` 實現（含 `Run[YourStrategy]SingleBacktest`）位於 `internal/saas/ga/[strategy]_evolvable.go`，**而非** `internal/strategies/[strategy]/`。原因：

- `backtest → [strategy]`（`adapter.go` 使用策略的 `Params`）
- `genome → [strategy]`（`store.go` 使用 `[strategy].StrategyID`）

若將 `[YourStrategy]Evolvable` 放入策略包，則策略包須導入 `ga` 與 `backtest`，形成雙重循環依賴。將其放在 `ga` 包內則無新循環（`ga` 已依賴策略包，為單向依賴）。
