基于移动窗口的指标平稳性优化¶
1. 均值非平稳性的解决(中心化)
- 通过 “当前值 - 移动窗口均值 / 中位数” 消除指标长期趋势偏移,中位数更适合有极端值的场景。
moving_mean函数计算移动窗口均值,moving_median函数计算移动窗口中位数;- 均值中心化:
raw_indicator[i] - moving_mean(...); - 中位数中心化:
raw_indicator[i] - moving_median(...),专门处理极端值导致的均值偏移。
2. 方差非平稳性的解决(标准化)
- 通过 “(中心化后的当前值)/ 移动窗口标准差” 消除波动幅度的突变,让方差稳定。
moving_std函数计算移动窗口标准差;- 双平稳化:
(raw_indicator[i] - 移动均值) / 移动标准差,同时解决均值和方差的非平稳问题。
3. 窗口长度的权衡关系
- 短窗口能最大化提升平稳性,但会丢失大量原始信息;长窗口保留信息多,但平稳性提升有限。
- 对比
WINDOW_SHORT=20(短窗口)和WINDOW_LONG=100(长窗口)的均值中心化效果; - 结果显示:短窗口的 “>512 天状态次数” 远少于长窗口,验证了 “短窗口平稳性更强” 的结论。
4. 平稳性的量化验证
- 通过观察指标在 “高于 / 低于中位数” 状态间的切换间隔,长期状态(如 > 512 天)次数越少,平稳性越好。
analyze_state_gaps函数统计状态切换间隔;- 输出结果聚焦 “>512 天状态次数”,直观展示不同优化方法的平稳性差异(原始指标次数最多,双平稳化次数最少)。
#include <algorithm>
#include <climits>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <random>
#include <vector>
using namespace std;
// 1. 计算基础指标
double calc_trend(const vector<double>& close, int start_idx, int lookback) {
double sum_x = 0.0, sum_y = 0.0, sum_xy = 0.0, sum_x2 = 0.0;
for (int i = 0; i < lookback; ++i) {
double x = i;
double y = close[start_idx - i];
sum_x += x;
sum_y += y;
sum_xy += x * y;
sum_x2 += x * x;
}
double denominator = lookback * sum_x2 - sum_x * sum_x;
return denominator == 0 ? 0.0
: (lookback * sum_xy - sum_x * sum_y) / denominator;
}
// 2. 移动窗口计算:均值(处理无极端值场景)
double moving_mean(const vector<double>& data, int end_idx, int window_len) {
int start_idx = end_idx - window_len + 1;
if (start_idx < 0) start_idx = 0; // 防止越界
double sum = 0.0;
for (int i = start_idx; i <= end_idx; ++i) {
sum += data[i];
}
return sum / (end_idx - start_idx + 1);
}
// 3. 移动窗口计算:中位数(处理有极端值场景)
double moving_median(const vector<double>& data, int end_idx, int window_len) {
int start_idx = end_idx - window_len + 1;
if (start_idx < 0) start_idx = 0;
vector<double> window_data;
for (int i = start_idx; i <= end_idx; ++i) {
window_data.push_back(data[i]);
}
sort(window_data.begin(), window_data.end());
int mid = window_data.size() / 2;
return (window_data.size() % 2 == 1)
? window_data[mid]
: (window_data[mid - 1] + window_data[mid]) / 2;
}
// 4. 移动窗口计算:标准差(用于方差平稳化)
double moving_std(const vector<double>& data, int end_idx, int window_len) {
int start_idx = end_idx - window_len + 1;
if (start_idx < 0) start_idx = 0;
int n = end_idx - start_idx + 1;
if (n < 2) return 1.0; // 避免除以0
// 先算均值
double mean = 0.0;
for (int i = start_idx; i <= end_idx; ++i) {
mean += data[i];
}
mean /= n;
// 算标准差
double sum_sq = 0.0;
for (int i = start_idx; i <= end_idx; ++i) {
sum_sq += pow(data[i] - mean, 2);
}
return sqrt(sum_sq / (n - 1)); // 样本标准差
}
// 5. 分析状态变化间隔
vector<int> analyze_state_gaps(const vector<double>& indicator,
double quantile) {
const int NGAPS = 11;
vector<int> gap_counts(NGAPS, 0);
vector<int> gap_bounds = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, INT_MAX};
if (indicator.empty()) return gap_counts;
int current_state = (indicator[0] >= quantile) ? 1 : 0;
int state_duration = 1;
for (size_t i = 1; i < indicator.size(); ++i) {
int new_state = (indicator[i] >= quantile) ? 1 : 0;
if (new_state == current_state) {
state_duration++;
} else {
for (int j = 0; j < NGAPS; ++j) {
if (state_duration <= gap_bounds[j]) {
gap_counts[j]++;
break;
}
}
current_state = new_state;
state_duration = 1;
}
}
// 统计最后一段状态
for (int j = 0; j < NGAPS; ++j) {
if (state_duration <= gap_bounds[j]) {
gap_counts[j]++;
break;
}
}
return gap_counts;
}
// 6. 生成带非平稳特征的模拟指标(模拟长期趋势偏移+波动突变)
void generate_nonstationary_indicator(int len, vector<double>& raw_indicator) {
random_device rd;
mt19937 gen(rd());
normal_distribution<double> noise(0, 0.5);
raw_indicator.resize(len);
double trend_drift = 0.0; // 长期趋势漂移
double volatility = 0.5; // 初始波动率
for (int i = 0; i < len; ++i) {
// 模拟前500个数据:缓慢向上漂移(均值非平稳)
if (i < 500) {
trend_drift += 0.002;
}
// 模拟500-1000个数据:快速向下漂移(均值非平稳)
else if (i < 1000) {
trend_drift -= 0.005;
}
// 模拟1000个数据后:波动率翻倍(方差非平稳)
if (i >= 1000) {
volatility = 1.0;
}
raw_indicator[i] = 2.0 + trend_drift + noise(gen) * volatility;
}
}
int main() {
// 配置参数
const int INDICATOR_LEN = 1500; // 指标数据长度
const int BASE_LOOKBACK = 50; // 基础回溯窗口(计算原始趋势指标)
const int WINDOW_SHORT = 20; // 短移动窗口(强平稳化,弱信息保留)
const int WINDOW_LONG = 100; // 长移动窗口(弱平稳化,强信息保留)
const double FRACTILE = 0.5; // 分位数(中位数,用于状态划分)
// 生成带非平稳特征的原始指标(模拟均值+方差非平稳)
vector<double> raw_indicator;
generate_nonstationary_indicator(INDICATOR_LEN, raw_indicator);
cout << "生成 " << INDICATOR_LEN << " 个数据点的非平稳原始指标" << endl
<< endl;
// 生成4类优化后的指标
enum IndicatorType {
RAW, // 原始指标(无优化)
CENTERED_MEAN, // 均值中心化(消除均值非平稳)
CENTERED_MEDIAN, // 中位数中心化(消除均值非平稳,抗极端值)
NORMALIZED_FULL // 均值中心化+标准差标准化(消除均值+方差非平稳)
};
vector<vector<double>> optimized_indicators(4);
// 计算各类指标
for (int i = 0; i < INDICATOR_LEN; ++i) {
// 原始指标
optimized_indicators[RAW].push_back(raw_indicator[i]);
// 1. 均值中心化(当前值 - 移动窗口均值)
double mean_win = moving_mean(raw_indicator, i, WINDOW_SHORT);
optimized_indicators[CENTERED_MEAN].push_back(raw_indicator[i] - mean_win);
// 2. 中位数中心化(当前值 - 移动窗口中位数,抗极端值)
double median_win = moving_median(raw_indicator, i, WINDOW_SHORT);
optimized_indicators[CENTERED_MEDIAN].push_back(raw_indicator[i] -
median_win);
// 3. 均值+方差双平稳化(中心化后 / 移动窗口标准差)
double std_win = moving_std(raw_indicator, i, WINDOW_SHORT);
double centered_val = raw_indicator[i] - mean_win;
optimized_indicators[NORMALIZED_FULL].push_back(centered_val / std_win);
}
// 对比短/长窗口对平稳性的影响(以均值中心化为例)
vector<double> centered_long_win;
for (int i = 0; i < INDICATOR_LEN; ++i) {
double mean_long = moving_mean(raw_indicator, i, WINDOW_LONG);
centered_long_win.push_back(raw_indicator[i] - mean_long);
}
// 分析所有指标的平稳性(统计状态变化间隔)
vector<string> indicator_names = {
"原始指标(无优化)", "短窗口均值中心化", "短窗口中位数中心化",
"短窗口均值+方差双平稳化", "长窗口均值中心化"};
vector<vector<double>> all_indicators = {
optimized_indicators[RAW], optimized_indicators[CENTERED_MEAN],
optimized_indicators[CENTERED_MEDIAN],
optimized_indicators[NORMALIZED_FULL], centered_long_win};
vector<vector<int>> gap_results(all_indicators.size());
for (size_t i = 0; i < all_indicators.size(); ++i) {
// 计算指标的中位数(分位数=0.5)
vector<double> sorted = all_indicators[i];
sort(sorted.begin(), sorted.end());
double quantile = sorted[sorted.size() / 2];
// 分析状态变化间隔
gap_results[i] = analyze_state_gaps(all_indicators[i], quantile);
}
// 输出结果(重点关注长期状态>512的次数,次数越少平稳性越好)
cout << "=== 各指标平稳性对比(长期状态>512天出现次数)===" << endl;
cout << setw(20) << "指标类型" << setw(15) << ">512天状态次数" << endl;
cout << string(35, '-') << endl;
for (size_t i = 0; i < indicator_names.size(); ++i) {
// >512天对应gap_results的第10个位置(索引从0开始)
cout << setw(20) << indicator_names[i] << setw(15) << gap_results[i][10]
<< endl;
}
// 输出结论
cout << "\n=== 核心结论 ===" << endl;
cout << "1. "
"均值/"
"中位数中心化:有效消除指标均值非平稳(原始指标>"
"512天次数最多,优化后显著减少)"
<< endl;
cout << "2. 均值+方差双平稳化:同时解决均值和方差非平稳(适合波动突变场景)"
<< endl;
cout << "3. 窗口长度权衡:短窗口(" << WINDOW_SHORT
<< ")平稳性更强,但丢失信息多;长窗口(" << WINDOW_LONG
<< ")保留信息多,但平稳性弱" << endl;
cout << "4. 中位数中心化:比均值中心化更抗极端值(极端值场景下平稳性更稳定)"
<< endl;
return 0;
}