差分进化优化:非线性参数寻优¶
1. 核心目标
针对交易系统中“规则化策略参数优化”的场景(如移动平均交叉系统的“长期/短期回溯期”“开仓阈值”),通过种群进化+局部爬山的混合算法,高效寻找全局最优参数组合,避免传统“网格搜索”效率低、易陷局部最优的问题。
2. 核心原理
(1)种群初始化:过度初始化提升质量
- 生成“种群规模+过度初始化数量”的参数组合(如种群100个,过度初始化100个),每个参数组合需满足“交易数≥min_trades”(避免“少数幸运交易获利”的无效参数);
- 过度初始化逻辑:对超出种群规模的参数组合,仅保留性能优于当前种群中最差个体的组合,提升初始种群整体质量,加速后续进化收敛。
(2)进化迭代:变异+交叉+选择(微分进化核心流程)
- 父代选择:为每个个体(参数组合)随机选择3个不同父代(parent2、diff1、diff2);
- 变异操作:生成子代参数:$ child_j = parent2_j + mutate_dev*(diff1_j - diff2_j) $(书中标准变异公式,
mutate_dev控制变异幅度),确保参数在合法边界内; - 交叉操作:随机选择起始参数,按
cross_prob概率用变异参数替换父代参数,保证子代兼具父代与变异特性; - 选择操作:若子代性能(由
trade_system_criter评估)优于父代,则替换父代,确保种群整体性能迭代提升。
(3)混合优化:局部爬山加速收敛
- 每代迭代后,按
climb_prob概率对个体(优先当前最优个体)执行“单参数爬山优化”: - 整数参数(如均线回溯期):逐值搜索上下边界,找到性能最优值;
- 实数参数(如开仓阈值):用简化Brent算法(三分法)快速定位局部最优;
- 该步骤结合“全局种群进化”与“局部精细搜索”,既避免陷局部最优,又提升最优参数的精度(“混合优化提升效率”的思想)。
(4)终止条件与结果输出
- 当“连续max_bad_gen代无性能提升”时停止迭代,输出全局最优参数组合及其性能(由
get_best获取),符合“稳定收敛即停止”的优化准则。
(5)性能评估接口: trade_system_criter
- 输入:待评估的参数组合(如均线回溯期、阈值)+ 最小交易数约束;
- 内部逻辑:按参数复现交易策略(如均线交叉开仓/平仓),计算回测期间性能(书中支持的总收益、夏普比率、盈利因子等),若交易数不足则返回无效值;
- 输出:量化性能评分,供优化算法比较不同参数组合的优劣。
#include <cmath>
#include <cstring>
#include <iostream>
#include <random>
#include <vector>
// 错误码定义
enum class DiffEvolutionErr {
SUCCESS = 0,
INVALID_PARAM = 1, // 参数范围非法、种群大小过小等
INSUFFICIENT_TRADES = 2, // 交易次数未达最小要求
MEMORY_FAILED = 3, // 内存分配失败
MAX_EVALS_EXCEEDED = 4 // 性能评估次数超出上限
};
// 性能评估函数类型(输入参数集,输出性能值)
typedef double (*PerformanceCriter)(const double* params, int min_trades,
void* user_data);
class DiffEvolution {
public:
/**
* @brief 构造函数:初始化差分进化优化器
* @param n_params 优化参数数
* @param n_int_params 前n_int_params个参数为整数(其余为实数)
* @param pop_size 种群大小(建议≥50)
* @param over_init 过初始化次数(建议=种群大小)
* @param min_trades 最小交易次数(低于此的参数集被拒绝)
* @param max_evals 最大性能评估次数(安全阈值)
* @param max_bad_gens 最大无改进代数(收敛判断)
* @param mutate_dev 变异系数(建议0.1~0.5)
* @param cross_prob 交叉概率(建议0.1~0.5)
* @param climb_prob 爬山法概率(建议0~0.2)
* @param low_bounds 参数下界
* @param high_bounds 参数上界
* @param criter 性能评估函数
* @param user_data 性能评估的用户数据(如市场价格)
* @param err_code 输出错误码指针(可为nullptr)
*/
DiffEvolution(int n_params, int n_int_params, int pop_size, int over_init,
int min_trades, int max_evals, int max_bad_gens,
double mutate_dev, double cross_prob, double climb_prob,
const double* low_bounds, const double* high_bounds,
PerformanceCriter criter, void* user_data,
DiffEvolutionErr* err_code = nullptr)
: n_params_(n_params),
n_int_params_(n_int_params),
pop_size_(pop_size),
over_init_(over_init),
min_trades_(min_trades),
max_evals_(max_evals),
max_bad_gens_(max_bad_gens),
mutate_dev_(mutate_dev),
cross_prob_(cross_prob),
climb_prob_(climb_prob),
criter_(criter),
user_data_(user_data),
pop1_(nullptr),
pop2_(nullptr),
best_params_(nullptr),
rng_(std::random_device{}()),
initialized_(false) {
DiffEvolutionErr err =
initialize(n_params, n_int_params, pop_size, over_init, min_trades,
max_evals, max_bad_gens, mutate_dev, cross_prob, climb_prob,
low_bounds, high_bounds);
if (err_code) *err_code = err;
}
private:
DiffEvolutionErr initialize(int n_params, int n_int_params, int pop_size,
int over_init, int min_trades, int max_evals,
int max_bad_gens, double mutate_dev,
double cross_prob, double climb_prob,
const double* low_bounds,
const double* high_bounds) {
// 参数合法性检查
if (n_params <= 0 || n_int_params < 0 || n_int_params > n_params ||
pop_size < 10 || over_init < 0 || min_trades < 1 ||
max_evals < pop_size + over_init || max_bad_gens < 10 ||
mutate_dev <= 0 || cross_prob < 0 || cross_prob > 1 || climb_prob < 0 ||
climb_prob > 1 || !low_bounds || !high_bounds) {
return DiffEvolutionErr::INVALID_PARAM;
}
for (int i = 0; i < n_params; ++i) {
if (low_bounds[i] >= high_bounds[i]) {
return DiffEvolutionErr::INVALID_PARAM;
}
}
// 内存分配(每个个体:n_params个参数 + 1个性能值)
int individual_size = n_params + 1;
pop1_ = new (std::nothrow) double[pop_size * individual_size]{};
pop2_ = new (std::nothrow) double[pop_size * individual_size]{};
best_params_ = new (std::nothrow) double[individual_size]{};
if (!pop1_ || !pop2_ || !best_params_) {
return DiffEvolutionErr::MEMORY_FAILED;
}
// 保存参数
n_params_ = n_params;
n_int_params_ = n_int_params;
pop_size_ = pop_size;
over_init_ = over_init;
min_trades_ = min_trades;
max_evals_ = max_evals;
max_bad_gens_ = max_bad_gens;
mutate_dev_ = mutate_dev;
cross_prob_ = cross_prob;
climb_prob_ = climb_prob;
// 保存参数边界
low_bounds_.resize(n_params);
high_bounds_.resize(n_params);
memcpy(low_bounds_.data(), low_bounds, n_params * sizeof(double));
memcpy(high_bounds_.data(), high_bounds, n_params * sizeof(double));
initialized_ = true;
return DiffEvolutionErr::SUCCESS;
}
public:
~DiffEvolution() {
delete[] pop1_;
delete[] pop2_;
delete[] best_params_;
}
/**
* @brief 执行差分进化优化
* @param best_params 输出:最优参数集(n_params个参数 + 1个性能值)
* @return DiffEvolutionErr 错误码
*/
DiffEvolutionErr optimize(double* best_params) {
if (!initialized_) return DiffEvolutionErr::INVALID_PARAM;
if (!best_params) return DiffEvolutionErr::INVALID_PARAM;
int individual_size = n_params_ + 1;
int eval_count = 0; // 性能评估计数器
int failures = 0; // 连续失败次数(参数集不满足最小交易次数)
// 1. 初始化种群
for (int ind = 0; ind < pop_size_ + over_init_; ++ind) {
double* curr_ind =
(ind < pop_size_) ? (pop1_ + ind * individual_size) : pop2_;
bool valid = false;
// 生成随机参数集(整数参数四舍五入,实数参数均匀分布)
while (!valid) {
// 检查评估次数上限
if (eval_count >= max_evals_) {
return DiffEvolutionErr::MAX_EVALS_EXCEEDED;
}
// 生成参数
for (int i = 0; i < n_params_; ++i) {
std::uniform_real_distribution<double> dist(low_bounds_[i],
high_bounds_[i]);
double val = dist(rng_);
// 整数参数处理
if (i < n_int_params_) {
val = std::round(val);
val = std::max(low_bounds_[i], std::min(high_bounds_[i], val));
}
curr_ind[i] = val;
}
// 评估性能
double perf = criter_(curr_ind, min_trades_, user_data_);
eval_count++;
curr_ind[n_params_] = perf;
// 检查有效性(性能>0且交易次数达标)
if (perf > 0) {
valid = true;
failures = 0;
} else {
failures++;
// 连续失败500次,降低最小交易次数
if (failures >= 500) {
min_trades_ = std::max(1, min_trades_ * 9 / 10);
failures = 0;
}
}
}
// 过初始化:替换种群中最差个体
if (ind >= pop_size_) {
// 找到种群中最差个体
int worst_idx = 0;
double worst_perf = pop1_[worst_idx * individual_size + n_params_];
for (int i = 1; i < pop_size_; ++i) {
double perf = pop1_[i * individual_size + n_params_];
if (perf < worst_perf) {
worst_perf = perf;
worst_idx = i;
}
}
// 替换最差个体
if (curr_ind[n_params_] > worst_perf) {
memcpy(pop1_ + worst_idx * individual_size, curr_ind,
individual_size * sizeof(double));
}
}
}
// 2. 初始化最优个体
memcpy(best_params_, pop1_, individual_size * sizeof(double));
for (int i = 1; i < pop_size_; ++i) {
double* ind = pop1_ + i * individual_size;
if (ind[n_params_] > best_params_[n_params_]) {
memcpy(best_params_, ind, individual_size * sizeof(double));
}
}
// 3. 进化迭代
double* old_gen = pop1_;
double* new_gen = pop2_;
int bad_gens = 0; // 无改进代数
int n_tweaked = 0; // 爬山法优化的参数计数
std::uniform_real_distribution<double> unif_dist(0.0, 1.0);
while (bad_gens < max_bad_gens_) {
bool improved = false;
double gen_best_perf = best_params_[n_params_];
// 遍历种群中每个个体作为父代1
for (int ind = 0; ind < pop_size_; ++ind) {
double* parent1 = old_gen + ind * individual_size;
double* child = new_gen + ind * individual_size;
// 随机选择父代2、差分1、差分2(互不相同且≠父代1)
int p2_idx, d1_idx, d2_idx;
do {
p2_idx = (int)(unif_dist(rng_) * pop_size_);
} while (p2_idx == ind);
do {
d1_idx = (int)(unif_dist(rng_) * pop_size_);
} while (d1_idx == ind || d1_idx == p2_idx);
do {
d2_idx = (int)(unif_dist(rng_) * pop_size_);
} while (d2_idx == ind || d2_idx == p2_idx || d2_idx == d1_idx);
double* parent2 = old_gen + p2_idx * individual_size;
double* diff1 = old_gen + d1_idx * individual_size;
double* diff2 = old_gen + d2_idx * individual_size;
// 变异与交叉
int start_idx = (int)(unif_dist(rng_) * n_params_); // 随机起始参数
bool used_mutate = false;
for (int i = 0; i < n_params_; ++i) {
int j = (start_idx + i) % n_params_;
if ((i == 0 && !used_mutate) || (unif_dist(rng_) < cross_prob_)) {
// 变异:child[j] = parent2[j] + mutate_dev*(diff1[j] - diff2[j])
double val = parent2[j] + mutate_dev_ * (diff1[j] - diff2[j]);
// 边界与类型修正
if (j < n_int_params_) {
val = std::round(val);
}
val = std::max(low_bounds_[j], std::min(high_bounds_[j], val));
child[j] = val;
used_mutate = true;
} else {
// 保留父代1参数
child[j] = parent1[j];
}
}
// 评估子代性能
if (eval_count >= max_evals_) {
return DiffEvolutionErr::MAX_EVALS_EXCEEDED;
}
double child_perf = criter_(child, min_trades_, user_data_);
eval_count++;
child[n_params_] = child_perf;
// 子代优于父代则替换
if (child_perf > parent1[n_params_]) {
// 检查是否更新全局最优
if (child_perf > best_params_[n_params_]) {
memcpy(best_params_, child, individual_size * sizeof(double));
improved = true;
n_tweaked = 0; // 重置爬山法计数
}
} else {
// 子代较差,保留父代
memcpy(child, parent1, individual_size * sizeof(double));
}
// 可选爬山法优化
if (climb_prob_ > 0 &&
(ind == get_best_idx(old_gen) || unif_dist(rng_) < climb_prob_)) {
if (ind == get_best_idx(old_gen)) {
// 对当前最优个体,循环优化每个参数
int tweak_idx = (n_tweaked++) % n_params_;
hill_climb(child, tweak_idx);
} else {
// 对随机个体,优化随机参数
int tweak_idx = (int)(unif_dist(rng_) * n_params_);
hill_climb(child, tweak_idx);
}
// 检查是否更新全局最优
if (child[n_params_] > best_params_[n_params_]) {
memcpy(best_params_, child, individual_size * sizeof(double));
improved = true;
n_tweaked = 0;
}
}
}
// 收敛判断:无改进则增加bad_gens,否则重置
if (improved) {
bad_gens = 0;
} else {
bad_gens++;
}
// 交换新旧种群
std::swap(old_gen, new_gen);
}
// 输出最优参数
memcpy(best_params, best_params_, individual_size * sizeof(double));
return DiffEvolutionErr::SUCCESS;
}
private:
/**
* @brief 爬山法优化单个参数
* @param ind 待优化个体
* @param param_idx 待优化参数索引
*/
void hill_climb(double* ind, int param_idx) {
if (param_idx < 0 || param_idx >= n_params_) return;
double original_val = ind[param_idx];
double original_perf = ind[n_params_];
double best_val = original_val;
double best_perf = original_perf;
// 整数参数:步长1,搜索上下界
if (param_idx < n_int_params_) {
// 向上搜索
for (double val = original_val + 1; val <= high_bounds_[param_idx];
val++) {
ind[param_idx] = val;
double perf = criter_(ind, min_trades_, user_data_);
if (perf > best_perf) {
best_perf = perf;
best_val = val;
} else {
break; // 性能下降则停止
}
}
// 向下搜索
for (double val = original_val - 1; val >= low_bounds_[param_idx];
val--) {
ind[param_idx] = val;
double perf = criter_(ind, min_trades_, user_data_);
if (perf > best_perf) {
best_perf = perf;
best_val = val;
} else {
break; // 性能下降则停止
}
}
} else {
// 实数参数:用Brent算法精细搜索
double left = low_bounds_[param_idx];
double right = high_bounds_[param_idx];
double tol = 1e-6;
int max_iter = 100;
// Brent算法核心逻辑(简化版)
double a = left, b = right;
double c = b, d = 0, e = 0;
double fa = eval_perf(ind, param_idx, a);
double fb = eval_perf(ind, param_idx, b);
double fc = fb;
for (int iter = 0; iter < max_iter; ++iter) {
if (fb > fa && fb > fc) break; // 当前b已是最优
double tol1 = tol * std::fabs(b) + 1e-10;
double xm = 0.5 * (a + c);
// 黄金分割或抛物线插值
if (std::fabs(e) > tol1) {
double r = (b - a) * (fb - fc);
double q = (b - c) * (fb - fa);
double p = (b - c) * q - (b - a) * r;
q = 2 * (q - r);
if (q > 0) p = -p;
q = std::fabs(q);
double etemp = e;
e = d;
if (std::fabs(p) < std::fabs(0.5 * q * etemp) && p > q * (a - b) &&
p < q * (b - c)) {
d = p / q; // 抛物线插值
} else {
d = (b < xm) ? tol1 : -tol1; // 黄金分割
}
} else {
d = (b < xm) ? tol1 : -tol1;
}
double u = b + d;
double fu = eval_perf(ind, param_idx, u);
if (fu > fb) {
best_perf = fu;
best_val = u;
a = b;
fa = fb;
b = u;
fb = fu;
} else {
c = b;
fc = fb;
b = u;
fb = fu;
}
}
}
// 恢复最优值
ind[param_idx] = best_val;
ind[n_params_] = best_perf;
}
/**
* @brief 评估参数值对应的性能
* @param ind 个体
* @param param_idx 参数索引
* @param val 参数值
* @return double 性能值
*/
double eval_perf(double* ind, int param_idx, double val) {
double original_val = ind[param_idx];
ind[param_idx] = val;
// 修正参数类型与边界
if (param_idx < n_int_params_) {
ind[param_idx] = std::round(val);
}
ind[param_idx] =
std::max(low_bounds_[param_idx],
std::min(high_bounds_[param_idx], ind[param_idx]));
// 评估性能
double perf = criter_(ind, min_trades_, user_data_);
// 恢复原始值(避免影响其他计算)
ind[param_idx] = original_val;
return perf;
}
/**
* @brief 获取种群中最优个体的索引
* @param gen 种群
* @return int 最优个体索引
*/
int get_best_idx(const double* gen) const {
int best_idx = 0;
int individual_size = n_params_ + 1;
double best_perf = gen[best_idx * individual_size + n_params_];
for (int i = 1; i < pop_size_; ++i) {
double perf = gen[i * individual_size + n_params_];
if (perf > best_perf) {
best_perf = perf;
best_idx = i;
}
}
return best_idx;
}
private:
int n_params_; // 优化参数数
int n_int_params_; // 整数参数数
int pop_size_; // 种群大小
int over_init_; // 过初始化次数
int min_trades_; // 最小交易次数
int max_evals_; // 最大性能评估次数
int max_bad_gens_; // 最大无改进代数
double mutate_dev_; // 变异系数
double cross_prob_; // 交叉概率
double climb_prob_; // 爬山法概率
PerformanceCriter criter_; // 性能评估函数
void* user_data_; // 用户数据
std::vector<double> low_bounds_; // 参数下界
std::vector<double> high_bounds_; // 参数上界
double* pop1_; // 种群1(父代)
double* pop2_; // 种群2(子代)
double* best_params_; // 当前最优个体
std::mt19937 rng_; // 随机数生成器
bool initialized_; // 是否初始化成功
};
#include "DiffEvolution.h"
// 测试用性能评估函数示例:寻找使函数f(x,y) = -(x-3)^2-(y-4)^2最大的点
double testFunction(const double* params, int min_trades, void* user_data) {
double x = params[0];
double y = params[1];
// 模拟交易次数检查
if (min_trades > 10) return -1; // 不满足最小交易次数
// 目标函数:寻找最大值点(3,4)
double result = -((x - 3) * (x - 3) + (y - 4) * (y - 4));
return -result; // 返回负值因为算法寻找最大值
}
// 测试函数
void runTest() {
std::cout << "开始差分进化算法测试...\n";
// 定义参数
const int n_params = 2;
const int n_int_params = 0;
const int pop_size = 50;
const int over_init = 50;
const int min_trades = 5;
const int max_evals = 1000;
const int max_bad_gens = 50;
const double mutate_dev = 0.5;
const double cross_prob = 0.3;
const double climb_prob = 0.1;
// 参数边界
double low_bounds[n_params] = {-10.0, -10.0};
double high_bounds[n_params] = {10.0, 10.0};
// 创建优化器实例(不使用异常)
DiffEvolutionErr err_code;
DiffEvolution optimizer(n_params, n_int_params, pop_size, over_init,
min_trades, max_evals, max_bad_gens, mutate_dev,
cross_prob, climb_prob, low_bounds, high_bounds,
testFunction, nullptr, &err_code);
if (err_code != DiffEvolutionErr::SUCCESS) {
std::cout << "优化器初始化失败,错误码: " << static_cast<int>(err_code)
<< "\n";
return;
}
// 执行优化
double best_params[n_params + 1];
DiffEvolutionErr result = optimizer.optimize(best_params);
if (result == DiffEvolutionErr::SUCCESS) {
std::cout << "优化成功!\n";
std::cout << "最佳参数: x = " << best_params[0]
<< ", y = " << best_params[1] << "\n";
std::cout << "最佳函数值: " << -best_params[2] << "\n"; // 转换回原函数值
} else {
std::cout << "优化失败,错误码: " << static_cast<int>(result) << "\n";
}
}
int main() {
runTest();
return 0;
}