《金融大模型开发与应用实践》的背景,我将详细阐述如何使用 C++ 实现基于梯度提升树(Gradient Boosting Trees)的分类器列表
《金融大模型开发与应用实践》的背景,我将详细阐述如何使用 C++ 实现基于梯度提升树(Gradient Boosting Trees)的分类器列表,用于预测苹果公司(AAPL)股票周收益的正负方向(分类任务:上涨为 1,下跌为 0)。我将结合您提到的多种梯度提升树算法(AdaBoost、Gradient Boosting、Histogram-based Gradient Boosting、CatBoost、XGBoost),并确保设置相同的随机种子(random_state=123)以保证结果可重复性。由于您提到使用 ROC-AUC 作为评估指标,我将实现相应的评估逻辑,并结合特征工程、模型训练、预测和交易策略评估。
5.7 构建模型
5.7.1 梯度提升树分类器列表
目标:构建一个包含多种梯度提升树分类器的列表,预测 AAPL 股票周收益的涨跌方向。
- 分类器:
- AdaBoost:通过迭代弱分类器(如决策树)加权组合,注重错误样本。
- Gradient Boosting:经典梯度提升树,优化损失函数(如对数损失)。
- Histogram-based Gradient Boosting:基于直方图的梯度提升(如 LightGBM),高效处理大规模数据。
- CatBoost:优化处理类别特征,适合金融数据的复杂特征。
- XGBoost:高性能梯度提升树,支持正则化和并行计算。
- 随机种子:设置
random_state=123以确保可重复性。 - 评估指标:ROC-AUC 分数,衡量模型区分上涨和下跌的能力。
- 数据:AAPL 30年历史数据,转换为周收益,特征包括滞后期、滚动统计、L-矩等。
C++ 的优势在于高效计算和低延迟,适合实时预测和交易场景。以下是具体实现步骤。
1. 数据准备
1.1 数据来源
- AAPL 历史数据:包含
{Date, Open, High, Low, Close, Volume},转换为周收益r_t = (Close_t - Close_{t-1}) / Close_{t-1}。 - 目标变量:将周收益二值化为分类标签:
y_t = 1(上涨):若r_t > 0。y_t = 0(下跌):若r_t <= 0。
- 时间范围:30年数据,预测最后 90 天(约 13 周)。
1.2 C++ 数据读取与标签生成
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <Eigen/Dense>
struct StockData {
std::string date;
double open, high, low, close, volume;
};
std::vector<StockData> loadStockData(const std::string& filename) {
std::vector<StockData> data;
std::ifstream file(filename);
std::string line;
std::getline(file, line); // 跳过表头
while (std::getline(file, line)) {
std::stringstream ss(line);
StockData row;
std::string token;
std::getline(ss, row.date, ',');
std::getline(ss, token, ','); row.open = std::stod(token);
std::getline(ss, token, ','); row.high = std::stod(token);
std::getline(ss, token, ','); row.low = std::stod(token);
std::getline(ss, token, ','); row.close = std::stod(token);
std::getline(ss, token, ','); row.volume = std::stod(token);
data.push_back(row);
}
file.close();
return data;
}
// 计算周收益并生成分类标签
struct LabeledData {
std::vector<double> returns;
Eigen::VectorXd labels; // 1: 上涨, 0: 下跌
};
LabeledData calculateWeeklyReturnsAndLabels(const std::vector<StockData>& data, int days_per_week = 5) {
LabeledData result;
for (size_t i = days_per_week; i < data.size(); i += days_per_week) {
double prev_close = data[i - days_per_week].close;
double curr_close = data[i].close;
double weekly_return = (curr_close - prev_close) / prev_close;
result.returns.push_back(weekly_return);
result.labels.conservativeResize(result.labels.size() + 1);
result.labels(result.labels.size() - 1) = (weekly_return > 0) ? 1.0 : 0.0;
}
return result;
}
1.3 特征工程
基于前述问题,特征包括:
- 滞后期:过去 1-4 周的收益、Open、Close、Volume、High。
- 滚动统计:5 周均值、标准差。
- L-矩:L-均值、L-方差。
- 技术指标:RSI、MACD。
struct FeatureData {
Eigen::VectorXd labels; // 分类标签
Eigen::MatrixXd features; // 特征矩阵
};
FeatureData prepareData(const std::vector<StockData>& data, int lag = 4, int window = 5) {
FeatureData result;
LabeledData labeled = calculateWeeklyReturnsAndLabels(data);
result.labels = labeled.labels;
Eigen::VectorXd returns = Eigen::Map<Eigen::VectorXd>(labeled.returns.data(), labeled.returns.size());
// 特征矩阵
int num_features = lag + 2 + 2 + 4 * (lag + 2); // 滞后 + 滚动统计 + L-矩 + 其他列
Eigen::MatrixXd features(returns.size(), num_features);
features.setZero();
// 滞后期
for (int i = 0; i < lag; ++i) {
for (size_t j = i + 1; j < returns.size(); ++j) {
features(j, i) = returns[j - i - 1];
}
}
// 滚动统计
Eigen::VectorXd rolling_mean = returns;
for (size_t i = window - 1; i < returns.size(); ++i) {
rolling_mean(i) = returns.segment(i - window + 1, window).mean();
}
features.col(lag) = rolling_mean;
features.col(lag + 1) = (returns - rolling_mean).array().square();
// L-矩
features.col(lag + 2).setConstant(returns.mean());
features.col(lag + 3).setConstant((returns.array() - returns.mean()).square().mean());
// 其他列(Open, Close, Volume, High)
std::vector<Eigen::VectorXd> other_cols;
for (const auto& col : {&StockData::open, &StockData::close, &StockData::volume, &StockData::high}) {
Eigen::VectorXd col_data(data.size());
for (size_t i = 0; i < data.size(); ++i) {
col_data(i) = (data[i].*col);
}
col_data = normalize(col_data);
other_cols.push_back(col_data);
for (int i = 0; i < lag; ++i) {
for (size_t j = i + 1; j < col_data.size(); ++j) {
features(j, lag + 4 + i) = col_data[j - i - 1];
}
}
Eigen::VectorXd col_mean = col_data;
for (size_t i = window - 1; i < col_data.size(); ++i) {
col_mean(i) = col_data.segment(i - window + 1, window).mean();
}
features.col(lag + 4 + lag) = col_mean;
features.col(lag + 4 + lag + 1) = (col_data - col_mean).array().square();
}
// 删除缺失值
int valid_rows = returns.size() - lag;
result.features = features.bottomRows(valid_rows);
result.labels = result.labels.tail(valid_rows);
return result;
}
Eigen::VectorXd normalize(const Eigen::VectorXd& data) {
double mean = data.mean();
double stddev = std::sqrt((data.array() - mean).square().sum() / data.size());
return (data.array() - mean) / stddev;
}
2. 梯度提升树分类器列表
我们将实现以下分类器:
- AdaBoost:使用简单的决策树作为弱分类器。
- Gradient Boosting:经典梯度提升,使用对数损失。
- Histogram-based Gradient Boosting:使用 LightGBM。
- XGBoost:高性能梯度提升。
- CatBoost:需通过 Python 接口调用,C++ 可加载预训练模型。
由于 C++ 原生支持有限,CatBoost 训练建议在 Python 中完成,导出模型后用 C++ 推理。
2.1 设置随机种子
C++ 中通过 std::mt19937 设置随机种子,确保结果可重复。
#include <random>
void setRandomSeed(int seed) {
std::mt19937 gen(seed);
std::srand(seed);
}
2.2 AdaBoost 实现
AdaBoost 通过加权弱分类器组合预测。
#include <Eigen/Dense>
class DecisionStump {
int feature_idx;
double threshold;
double polarity;
public:
DecisionStump() : feature_idx(0), threshold(0.0), polarity(1.0) {}
void fit(const Eigen::MatrixXd& X, const Eigen::VectorXd& y, const Eigen::VectorXd& weights) {
double min_error = std::numeric_limits<double>::infinity();
for (int i = 0; i < X.cols(); ++i) {
for (int j = 0; j < X.rows(); ++j) {
double thresh = X(j, i);
for (double p : {1.0, -1.0}) {
double error = 0.0;
for (int k = 0; k < X.rows(); ++k) {
double pred = (p * X(k, i) < p * thresh) ? 1.0 : 0.0;
error += weights(k) * (pred != y(k));
}
if (error < min_error) {
min_error = error;
feature_idx = i;
threshold = thresh;
polarity = p;
}
}
}
}
}
Eigen::VectorXd predict(const Eigen::MatrixXd& X) {
Eigen::VectorXd preds(X.rows());
for (int i = 0; i < X.rows(); ++i) {
preds(i) = (polarity * X(i, feature_idx) < polarity * threshold) ? 1.0 : 0.0;
}
return preds;
}
};
class AdaBoost {
std::vector<DecisionStump> stumps;
std::vector<double> alpha;
public:
void fit(const Eigen::MatrixXd& X, const Eigen::VectorXd& y, int n_estimators) {
Eigen::VectorXd weights = Eigen::VectorXd::Constant(X.rows(), 1.0 / X.rows());
for (int i = 0; i < n_estimators; ++i) {
DecisionStump stump;
stump.fit(X, y, weights);
Eigen::VectorXd preds = stump.predict(X);
double error = ((preds.array() != y.array()).cast<double>() * weights).sum();
alpha.push_back(0.5 * std::log((1.0 - error) / error));
weights = weights.array() * (preds.array() == y.array()).cast<double>().exp().array() * std::exp(-alpha.back());
weights /= weights.sum();
stumps.push_back(stump);
}
}
Eigen::VectorXd predict(const Eigen::MatrixXd& X) {
Eigen::VectorXd preds = Eigen::VectorXd::Zero(X.rows());
for (size_t i = 0; i < stumps.size(); ++i) {
preds += alpha[i] * stumps[i].predict(X);
}
return (preds.array() > 0).cast<double>();
}
};
2.3 XGBoost 实现
使用 XGBoost C++ API。
#include <xgboost/c_api.h>
void trainXGBoost(const Eigen::MatrixXd& X_train, const Eigen::VectorXd& y_train, const std::string& model_path) {
DMatrixHandle dtrain;
XGDMatrixCreateFromMat(X_train.data(), X_train.rows(), X_train.cols(), &dtrain);
XGDMatrixSetFloatInfo(dtrain, "label", y_train.data(), y_train.size());
BoosterHandle booster;
XGBoosterCreate(&dtrain, 1, &booster);
XGBoosterSetParam(booster, "objective", "binary:logistic");
XGBoosterSetParam(booster, "max_depth", "6");
XGBoosterSetParam(booster, "eta", "0.3");
XGBoosterSetParam(booster, "seed", "123");
for (int i = 0; i < 100; ++i) {
XGBoosterUpdateOneIter(booster, i, dtrain);
}
XGBoosterSaveModel(booster, model_path.c_str());
XGBoosterFree(booster);
XGDMatrixFree(dtrain);
}
Eigen::VectorXd predictXGBoost(const Eigen::MatrixXd& X_test, const std::string& model_path) {
DMatrixHandle dtest;
XGDMatrixCreateFromMat(X_test.data(), X_test.rows(), X_test.cols(), &dtest);
BoosterHandle booster;
XGBoosterLoadModel(model_path.c_str(), &booster);
bst_ulong out_len;
const float* out_result;
XGBoosterPredict(booster, dtest, 0, 0, &out_len, &out_result);
Eigen::VectorXd preds(out_len);
for (bst_ulong i = 0; i < out_len; ++i) {
preds(i) = out_result[i] > 0.5 ? 1.0 : 0.0;
}
XGBoosterFree(booster);
XGDMatrixFree(dtest);
return preds;
}
2.4 LightGBM 实现(Histogram-based Gradient Boosting)
#include <lightgbm.h>
void trainLightGBM(const Eigen::MatrixXd& X_train, const Eigen::VectorXd& y_train, const std::string& model_path) {
DatasetHandle dataset;
LGBM_DatasetCreateFromMat(X_train.data(), C_API_DTYPE_FLOAT64, X_train.rows(), X_train.cols(), 1, nullptr, nullptr, &dataset);
LGBM_DatasetSetField(dataset, "label", y_train.data(), y_train.size(), C_API_DTYPE_FLOAT64);
BoosterHandle booster;
LGBM_BoosterCreate(dataset, "objective=binary metric=auc seed=123 num_leaves=31 learning_rate=0.05 num_iterations=100", &booster);
for (int i = 0; i < 100; ++i) {
int is_finished;
LGBM_BoosterUpdateOneIter(booster, &is_finished);
}
LGBM_BoosterSaveModel(booster, 0, -1, C_API_FEATURE_IMPORTANCE_GAIN, model_path.c_str());
LGBM_BoosterFree(booster);
LGBM_DatasetFree(dataset);
}
Eigen::VectorXd predictLightGBM(const Eigen::MatrixXd& X_test, const std::string& model_path) {
BoosterHandle booster;
LGBM_BoosterLoadModelFromFile(model_path.c_str(), nullptr, &booster);
int64_t out_len;
Eigen::VectorXd predictions(X_test.rows());
LGBM_BoosterPredictForMat(booster, X_test.data(), C_API_DTYPE_FLOAT64, X_test.rows(), X_test.cols(), 1,
C_API_PREDICT_NORMAL, 0, "", &out_len, predictions.data());
LGBM_BoosterFree(booster);
return (predictions.array() > 0.5).cast<double>();
}
2.5 CatBoost(通过 Python 预训练)
CatBoost 训练需在 Python 中完成,导出模型后用 C++ 推理。
#include <catboost/c_api.h>
Eigen::VectorXd predictCatBoost(const Eigen::MatrixXd& X_test, const std::string& model_path) {
ModelHandle model = CatBoostLoadModel(model_path.c_str());
Eigen::VectorXd predictions(X_test.rows());
CatBoostPredict(model, X_test.data(), X_test.rows(), X_test.cols(), predictions.data());
CatBoostFreeModel(model);
return (predictions.array() > 0.5).cast<double>();
}
3. 模型训练与评估
3.1 数据划分
- 训练集:80% 数据。
- 验证集:10% 数据,用于超参数调优。
- 测试集:最后 90 天(约 13 周)。
FeatureData splitData(const FeatureData& data) {
int train_size = static_cast<int>(data.features.rows() * 0.8);
int val_size = static_cast<int>(data.features.rows() * 0.1);
FeatureData split;
split.features = data.features.topRows(train_size); // 训练集特征
split.labels = data.labels.head(train_size); // 训练集标签
split.features.conservativeResize(data.features.rows(), data.features.cols());
split.features.middleRows(train_size, val_size) = data.features.middleRows(train_size, val_size); // 验证集
split.labels.conservativeResize(data.labels.size());
split.labels.segment(train_size, val_size) = data.labels.segment(train_size, val_size);
split.features.bottomRows(data.features.rows() - train_size - val_size) = data.features.bottomRows(data.features.rows() - train_size - val_size); // 测试集
split.labels.tail(data.labels.size() - train_size - val_size) = data.labels.tail(data.labels.size() - train_size - val_size);
return split;
}
3.2 ROC-AUC 评估
计算 ROC-AUC 分数以评估分类器性能。
double calculateROCAUC(const Eigen::VectorXd& y_true, const Eigen::VectorXd& y_scores) {
std::vector<std::pair<double, int>> pairs(y_true.size());
for (int i = 0; i < y_true.size(); ++i) {
pairs[i] = {y_scores(i), (int)y_true(i)};
}
std::sort(pairs.begin(), pairs.end(), std::greater<>());
double auc = 0.0;
int pos = 0, neg = 0;
for (const auto& p : pairs) {
if (p.second == 1) {
pos++;
} else {
neg++;
auc += pos;
}
}
return auc / (pos * neg);
}
3.3 训练与预测
void trainAndEvaluate(const std::vector<StockData>& data) {
setRandomSeed(123); // 设置随机种子
FeatureData prepared = prepareData(data);
FeatureData split = splitData(prepared);
Eigen::MatrixXd X_train = split.features.topRows(split.features.rows() * 0.8);
Eigen::VectorXd y_train = split.labels.head(split.labels.size() * 0.8);
Eigen::MatrixXd X_val = split.features.middleRows(split.features.rows() * 0.8, split.features.rows() * 0.1);
Eigen::VectorXd y_val = split.labels.segment(split.labels.size() * 0.8, split.labels.size() * 0.1);
Eigen::MatrixXd X_test = split.features.bottomRows(split.features.rows() - split.features.rows() * 0.9);
Eigen::VectorXd y_test = split.labels.tail(split.labels.size() - split.labels.size() * 0.9);
// 训练 AdaBoost
AdaBoost ada;
ada.fit(X_train, y_train, 50);
Eigen::VectorXd ada_preds = ada.predict(X_val);
std::cout << "AdaBoost ROC-AUC: " << calculateROCAUC(y_val, ada_preds) << std::endl;
// 训练 XGBoost
trainXGBoost(X_train, y_train, "xgboost_model.bin");
Eigen::VectorXd xgb_preds = predictXGBoost(X_val, "xgboost_model.bin");
std::cout << "XGBoost ROC-AUC: " << calculateROCAUC(y_val, xgb_preds) << std::endl;
// 训练 LightGBM
trainLightGBM(X_train, y_train, "lightgbm_model.bin");
Eigen::VectorXd lgb_preds = predictLightGBM(X_val, "lightgbm_model.bin");
std::cout << "LightGBM ROC-AUC: " << calculateROCAUC(y_val, lgb_preds) << std::endl;
// 测试集预测(以 LightGBM 为例)
Eigen::VectorXd test_preds = predictLightGBM(X_test, "lightgbm_model.bin");
std::cout << "Test ROC-AUC: " << calculateROCAUC(y_test, test_preds) << std::endl;
}
4. 交易策略
- 策略 I:仅在预测上涨(
y_pred = 1)时买入。 - 策略 II:预测上涨时做多,预测下跌时做空。
double evaluateStrategy(const std::vector<double>& returns, const Eigen::VectorXd& predictions, int strategy) {
double cum_return = 1.0;
for (size_t i = 0; i < returns.size(); ++i) {
if (strategy == 1) {
if (predictions(i) == 1) {
cum_return *= (1.0 + returns[i]);
}
} else {
cum_return *= (predictions(i) == 1) ? (1.0 + returns[i]) : (1.0 - returns[i]);
}
}
return cum_return - 1.0;
}
5. 与 Python 的结合
- CatBoost 训练:在 Python 中使用
catboost库训练,导出模型到 C++。 - 数据预处理:Python(Pandas、NumPy)处理复杂特征,导出 CSV。
- 推理:C++ 的 XGBoost 和 LightGBM API 实现高效预测。
6. 示例结果
基于 AAPL 最近 90 天数据:
- 周收益(示例):
- 2025-09-16:0.0068(上涨,标签 1)
- 2025-09-23:0.0684(上涨,标签 1)
- 2025-09-30:-0.0026(下跌,标签 0)
- 2025-10-13:-0.0246(下跌,标签 0)
- 模型性能(假设):
- AdaBoost ROC-AUC:0.75
- XGBoost ROC-AUC:0.82
- LightGBM ROC-AUC:0.85
- 交易策略:
- 策略 I 累积回报:5%
- 策略 II 累积回报:8%
7. 总结
C++ 实现梯度提升树分类器列表的流程包括:
- 数据准备:读取 AAPL 数据,计算周收益,生成分类标签。
- 特征工程:提取滞后、滚动统计、L-矩等特征。
- 模型训练:实现 AdaBoost、XGBoost、LightGBM,确保随机种子一致。
- 评估:使用 ROC-AUC 评估模型性能。
- 交易策略:基于预测结果执行策略 I 和 II。
C++ 的高性能适合实时预测,结合 Python 的训练生态可提升开发效率。如果需要更详细的代码(如 CatBoost 推理或策略优化),请进一步说明!
更多推荐


所有评论(0)