跳转至

基于移动窗口的指标平稳性优化

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;
}