快速开始
本演练从一个小型内存帧走到一份渲染好的报表。数值是合成的,不下载行情数据;其中任何内容都不构成投资结论。
构建收益序列并读取几个数字
#include <fincore/dataframe.hpp>
#include <fincore/metrics/drawdown.hpp>
#include <fincore/metrics/ratios.hpp>
#include <cstdio>
#include <vector>
int main() {
const std::vector<fincore::timestamp> index{
fincore::utc_timestamp(2025, 1, 2),
fincore::utc_timestamp(2025, 1, 3),
fincore::utc_timestamp(2025, 1, 6),
fincore::utc_timestamp(2025, 1, 7)};
fincore::dataframe returns;
returns.load_index(std::vector<fincore::timestamp>(index));
returns.load_column<double>(
"returns", {0.012, -0.02, 0.005, 0.03},
hmdf::nan_policy::dont_pad_with_nans);
std::printf("sharpe %.4f\n", fincore::sharpe_ratio(returns, "returns"));
std::printf("max dd %.4f\n", fincore::max_drawdown(returns, "returns"));
return 0;
}
有三点值得注意:
索引是显式给出的;
utc_timestamp会校验日历日期,并拒绝无法表示的日期。dont_pad_with_nans按原样保留数值。若改用补齐策略,缺失位置会被填入NaN。指标函数需要列名。传入不存在的列,或不是
double的列,都会抛input_error—— 拼写错误不会静默通过。
准备因子面板
analyze_factor 接受 prepared_factor_data:行、前瞻标签与清洗损失报告。每行的 forward_returns 必须按位置与 forward_labels 对齐。
#include <fincore/factor/analysis.hpp>
fincore::prepared_factor_data data;
data.forward_labels = {"1D", "5D"};
const auto start = fincore::utc_timestamp(2022, 1, 3);
const auto day = 86'400'000'000'000LL;
const char* assets[] = {"ALPHA", "BETA", "GAMMA", "DELTA", "EPSILON"};
for (int date = 0; date < 40; ++date) {
for (int asset = 0; asset < 5; ++asset) {
fincore::factor_row row;
row.date = start + date * day;
row.asset = assets[asset];
row.factor = 0.01 * static_cast<double>(asset) -
0.02 * static_cast<double>(date % 7);
row.quantile = asset + 1; // caller-supplied bucket
row.forward_returns = {0.001 * (date % 5),
0.002 * (asset % 3)}; // aligned with 1D, 5D
data.rows.push_back(row);
}
}
fincore::factor_analysis_config config;
config.periods = {"1D", "5D"};
config.turnover_periods = {1, 5};
config.include_portfolio_inputs = false;
const auto model = fincore::analyze_factor(data, config);
quantile 由调用方给出而不是计算得到:分析研究的是你声明的分桶。periods 必须是已准备的标签,而 forward_returns 按位置与 forward_labels 对齐,所以这里的两个列表描述的是同样顺序的同样列。
渲染报表
#include <fincore/factor/report.hpp>
#include <fincore/report/html.hpp>
#include <fincore/report/xlsx.hpp>
#include <fstream>
#include <string>
const auto document = fincore::build_factor_report(model, "Factor Report");
fincore::report_html_options options;
options.language = "en"; // "zh" for the Chinese labels
const std::string html = fincore::render_html(document, options);
const std::string workbook = fincore::render_xlsx(document);
std::ofstream{"factor_report.html", std::ios::binary} << html;
std::ofstream{"factor_report.xlsx", std::ios::binary} << workbook;
同一个 report_document 驱动所有后端。render_html 用同一模型为每种语言各产出一份文件,而 render_xlsx、render_pdf_bytes、render_plotly、render_bokeh 与 render_matplotlib 是它的其他视图。对确定性后端来说,渲染两次得到的字节完全一致,这正是报表可以被哈希与比较的原因。
在出错处处理失败
#include <fincore/error.hpp>
try {
const double sharpe = fincore::sharpe_ratio(returns, "missing");
(void)sharpe;
} catch (const fincore::input_error& error) {
std::fprintf(stderr, "rejected: %s (%s)\n", error.what(),
error.code().c_str());
}
结构性问题会抛出异常;本身合法但无法算出该统计量的序列返回 NaN。前者用 fincore::fincore_error 捕获,后者用 std::isnan 判断。
后续步骤
数据与数值约定 —— 时间戳、
NaN、所有权、摘要与错误模型。指标与滚动窗口 —— 该用哪个比率,以及它们各自如何处理缺失数据。
组合、风险、优化与模拟 —— 风险估计量及其状态。
因子研究 —— IC、分位、tears 与导出。
API 参考 —— 每个函数及其确切契约。