feat(11-04): 实现权重网格搜索优化功能

- History.php model 新增 _optimizeWeightsGridSearch 方法
- 5种预定义权重配置:遗漏优先型、转移概率优先型、走势方向优先型、平衡型、组合特征优先型
- 优化目标:综合得分 = hit_rate*0.6 + ndcg_5*100*0.4
- 超时保护机制:默认60秒,超时后停止剩余配置测试

- History.php controller 新增 optimizeWeights 接口入口
- 参数验证:periods(50-500)、backtest(10-100)、timeout(10-120)
- 超时警告提示
This commit is contained in:
2026-05-01 15:16:57 +08:00
parent 0221c596b1
commit e61d98607f
2 changed files with 306 additions and 1 deletions
+158
View File
@@ -3901,5 +3901,163 @@ class History extends Model
return max(0, min(1, $concentration));
}
/**
* 权重网格搜索优化
*
* 优化目标定义:
* - 综合评估得分 = hit_rate * 0.6 + ndcg_5 * 100 * 0.4
* - 命中率权重60%NDCG权重40%
* - 返回综合得分最高的权重配置
*
* 5种预定义权重配置:
* - 配置1: 遗漏优先型 - omit_regression权重最高(0.25)
* - 配置2: 转移概率优先型 - transition_prob权重最高(0.25)
* - 配置3: 走势方向优先型 - trend_direction权重最高(0.25)
* - 配置4: 平衡型 - 各维度权重较均衡
* - 配置5: 组合特征优先型 - combination权重最高(0.20)
*
* @param int $periods 统计期数,范围50-500
* @param int $backtestCount 回测期数,范围10-100
* @param int $timeoutSeconds 超时限制秒数,默认60秒
* @return array {best_weights: [], best_hit_rate: float, best_ndcg: float, all_results: [], timed_out: bool}
*/
private function _optimizeWeightsGridSearch($periods = 200, $backtestCount = 50, $timeoutSeconds = 60)
{
// 超时保护:记录开始时间
$startTime = microtime(true);
$timedOut = false;
// 5种预定义权重配置(具体权重值明确)
$weightConfigs = [
// 配置1: 遗漏优先型 - 遗漏回归权重最高
[
'omit_regression' => 0.25, // 遗漏回归权重25%
'freq_regression' => 0.12, // 频率回归权重12%
'transition_prob' => 0.15, // 转移概率权重15%
'trend_direction' => 0.12, // 走势方向权重12%
'oddeven_balance' => 0.08, // 单双平衡权重8%
'bigsmall_balance' => 0.08, // 大小平衡权重8%
'zone_balance' => 0.05, // 区域平衡权重5%
'color_balance' => 0.05, // 波色平衡权重5%
'combination' => 0.10 // 组合特征权重10%
],
// 配置2: 转移概率优先型 - 转移概率权重最高
[
'omit_regression' => 0.15,
'freq_regression' => 0.10,
'transition_prob' => 0.25, // 转移概率权重25%(最高)
'trend_direction' => 0.12,
'oddeven_balance' => 0.08,
'bigsmall_balance' => 0.08,
'zone_balance' => 0.04,
'color_balance' => 0.04,
'combination' => 0.14
],
// 配置3: 走势方向优先型 - 走势方向权重最高
[
'omit_regression' => 0.12,
'freq_regression' => 0.10,
'transition_prob' => 0.15,
'trend_direction' => 0.25, // 走势方向权重25%(最高)
'oddeven_balance' => 0.08,
'bigsmall_balance' => 0.08,
'zone_balance' => 0.04,
'color_balance' => 0.04,
'combination' => 0.12
],
// 配置4: 平衡型(默认配置)- 各维度权重较均衡
[
'omit_regression' => 0.18,
'freq_regression' => 0.12,
'transition_prob' => 0.18,
'trend_direction' => 0.14,
'oddeven_balance' => 0.08,
'bigsmall_balance' => 0.08,
'zone_balance' => 0.04,
'color_balance' => 0.04,
'combination' => 0.10
],
// 配置5: 组合特征优先型 - 组合特征权重最高
[
'omit_regression' => 0.15,
'freq_regression' => 0.10,
'transition_prob' => 0.15,
'trend_direction' => 0.12,
'oddeven_balance' => 0.06,
'bigsmall_balance' => 0.06,
'zone_balance' => 0.03,
'color_balance' => 0.03,
'combination' => 0.20 // 组合特征权重20%(最高)
]
];
$bestWeights = [];
$bestHitRate = 0;
$bestNdcg = 0;
$bestCombinedScore = 0;
$allResults = [];
// 执行每种配置的回测(添加超时检查)
foreach ($weightConfigs as $configIdx => $weights) {
// 超时检查:超过限制时间则停止
$elapsedTime = microtime(true) - $startTime;
if ($elapsedTime > $timeoutSeconds) {
$timedOut = true;
break;
}
// 执行回测
$backtest = $this->_runBacktestV3($periods, $weights, $backtestCount);
$hitRate = $backtest['hit_rate'] ?? 0;
$ndcg = $backtest['ndcg_5'] ?? 0;
$avgRank = $backtest['avg_rank'] ?? 0;
$mrr = $backtest['mrr'] ?? 0;
// 综合评估得分:命中率60% + NDCG40%
$combinedScore = $hitRate * 0.6 + $ndcg * 100 * 0.4;
$result = [
'config_name' => $configIdx + 1,
'config_type' => ['遗漏优先型', '转移概率优先型', '走势方向优先型', '平衡型', '组合特征优先型'][$configIdx],
'weights' => $weights,
'hit_rate' => $hitRate,
'avg_rank' => $avgRank,
'ndcg_5' => $ndcg,
'mrr' => $mrr,
'combined_score' => round($combinedScore, 2),
'total_hits' => $backtest['total_hits'] ?? 0
];
$allResults[] = $result;
// 更新最优配置
if ($combinedScore > $bestCombinedScore) {
$bestCombinedScore = $combinedScore;
$bestHitRate = $hitRate;
$bestNdcg = $ndcg;
$bestWeights = $weights;
}
}
// 按综合得分降序排序结果
usort($allResults, function($a, $b) {
return $b['combined_score'] - $a['combined_score'];
});
return [
'best_weights' => $bestWeights,
'best_hit_rate' => $bestHitRate,
'best_ndcg' => $bestNdcg,
'best_combined_score' => round($bestCombinedScore, 2),
'all_results' => $allResults,
'periods' => $periods,
'backtest_count' => $backtestCount,
'timeout_seconds' => $timeoutSeconds,
'timed_out' => $timedOut,
'elapsed_time' => round(microtime(true) - $startTime, 2)
];
}
}