Rust statrs

2025-05-17

statrs 是一个强大的 Rust 统计计算库,除了计算平均值外,它提供了许多专业级的统计函数。以下是它的主要亮点功能和使用示例:


1. 基础统计量(一键计算)

use statrs::statistics::Statistics;

let data = [0.07, 0.14, 0.13, 0.16, 0.12, 0.17, 0.22];

// 均值
let mean = data.mean();

// 中位数
let median = data.median(); 

// 方差和标准差
let variance = data.variance().unwrap();
let std_dev = data.std_dev().unwrap();

// 极值
let min = data.min();
let max = data.max();

2. 概率分布(内置20+分布)

use statrs::distribution::{Normal, Continuous};

// 创建正态分布 (均值=0, 标准差=1)
let normal = Normal::new(0.0, 1.0).unwrap();

// 计算PDF/ CDF
let pdf = normal.pdf(1.96);    // x=1.96处的概率密度
let cdf = normal.cdf(1.96);    // P(X ≤ 1.96)

// 生成随机样本
use rand;
let samples = normal.sample(&mut rand::thread_rng(), 100); 

支持的分布包括:

  • 正态分布 (Normal)
  • 泊松分布 (Poisson)
  • 二项分布 (Binomial)
  • t分布 (StudentsT)
  • 伽马分布 (Gamma)

3. 假设检验

use statrs::statistics::Distribution;
use statrs::statistics::Test;

// t检验(比较两组数据)
let group_a = [0.1, 0.2, 0.15];
let group_b = [0.3, 0.25, 0.4];
let t_test = statrs::statistics::t_test(&group_a, &group_b);

match t_test {
    Ok(result) => println!("p值: {}", result.p_value),
    Err(e) => eprintln!("检验失败: {}", e),
}

4. 分位数与排序统计

// 四分位数
let q1 = data.percentile(25);  // 第一四分位数
let q3 = data.percentile(75);  // 第三四分位数

// 任意分位
let p99 = data.percentile(99); // 99%分位点

5. 高级数学函数

use statrs::function::gamma;

// 伽马函数
gamma::gamma(5.0); // 4! = 24

// 贝塔函数
statrs::function::beta::beta(2.0, 5.0);

// 误差函数
statrs::function::erf::erf(1.0); 

6. 数据预处理

// 数据标准化 (Z-score)
let standardized: Vec<_> = data.iter().map(|x| (x - mean) / std_dev).collect();

// 归一化到[0,1]
let min = data.min();
let max = data.max();
let normalized: Vec<_> = data.iter().map(|x| (x - min)/(max - min)).collect();

性能优化特性

  1. 惰性计算:复杂统计量只在调用时计算
  2. SIMD加速:对大型数据集自动向量化计算
  3. 内存安全:所有操作零成本抽象

与类似库对比

特性 statrs nalgebra-stats smartcore
统计量完备性 ★★★★★ ★★★☆☆ ★★★★☆
概率分布支持 ★★★★★ ★★☆☆☆ ★★★☆☆
机器学习整合 ★☆☆☆☆ ★★★☆☆ ★★★★★
数值稳定性 ★★★★★ ★★★★☆ ★★★☆☆

安装建议

Cargo.toml 中添加:

[dependencies]
statrs = "0.16"
rand = "0.8"  # 如需生成随机样本

如果你的项目需要:

  • 金融分析 → 用它的分布和分位数计算
  • 科学计算 → 假设检验+高级数学函数
  • 数据工程 → 基础统计量+标准化工具

statrs 会是比手动实现更专业的选择。尤其适合需要高精度数值计算的场景。

在分析BTC/USDT价格时,你观察到的方差(3878)和标准差(62.27)相对于当前价格(103,639)显得很小的现象是正常的,这背后有深刻的统计学和金融逻辑。以下是详细解释:


1. 数值合理性的数学解释

  • 方差 (3878)
    计算的是价格与均值 平方差 的平均值,单位是「美元²」。
    示例:若价格在103,639 ± 62美元波动,方差 ≈ (62)² = 3844,与你的结果一致。

  • 标准差 (62.27)
    表示价格平均波动 ±62美元(约 0.06% 的波动幅度),对于BTC这种高市值资产,1小时内0.06%的波动属于正常范围。


2. 加密货币市场的典型波动特征

时间框架 预期标准差(BTC) 波动性质
1小时 0.05%~0.15% 短期噪音、流动性调整
日线 1%~3% 常规趋势波动
周线 5%~10% 重大事件或趋势转变

你的标准差 62.27/103639 ≈ 0.06% 完全符合1小时数据的典型波动范围。


3. 为什么看起来「小」?

(1) 绝对值 vs 相对值

  • 视觉偏差:103,639的「大价格」使62美元的波动显得微不足道,但实际上:
    // 计算波动百分比
    let volatility_pct = (std_dev / current_price) * 100.0; // ≈ 0.06%
    

(2) 对比传统市场

  • BTC 1小时波动:0.06%
  • 标普500 1小时波动:通常 <0.02%
    BTC的波动已是传统资产的3倍以上

4. 如何提高分析敏感度?

(1) 改用对数收益率

// 计算对数收益率序列
let log_returns: Vec<_> = prices
    .windows(2)
    .map(|w| (w[1] / w[0]).ln())
    .collect();

// 此时标准差表示收益率波动(更直观)
let ret_std = log_returns.std_dev().unwrap(); // 例如 0.0006(即0.06%)

(2) 滚动波动率分析

// 计算20小时滚动波动率
let rolling_volatility: Vec<_> = prices
    .windows(20)
    .map(|w| w.std_dev().unwrap() / w.mean().unwrap())
    .collect();

(3) 年化波动率

// 假设1小时数据,年化因子 = sqrt(24*365)
let annualized_vol = std_dev * (24.0 * 365.0).sqrt(); 
// 62.27 → ≈ 6096(即约6%年化波动率)

5. 实际交易中的应用建议

(1) 动态止损设置

// 2倍标准差作为止损区间
let stop_loss = current_price - 2.0 * std_dev; // 103639 - 124 = 103515

(2) 突破交易确认

// 只有突破幅度 > 3倍标准差才确认有效
let breakout_threshold = 3.0 * std_dev; // ≈186美元

(3) 仓位管理

// 波动率调整仓位(波动越大仓位越小)
let position_size = (capital * 0.01) / (std_dev / current_price); // 基于波动百分比

6. 与其他指标对比验证

// 检查布林带宽度(通常2倍标准差)
let ma = prices.mean().unwrap();
let upper_band = ma + 2.0 * std_dev;
let lower_band = ma - 2.0 * std_dev;
println!("布林带宽度: {:.2}%", (upper_band - lower_band) / ma * 100.0);
// 输出示例: "布林带宽度: 0.24%"

总结

  • 你的计算结果完全正确,小数值反映了BTC在1小时级别的典型波动特性。
  • 关键不是绝对大小,而是波动率相对于:
    • 历史波动水平
    • 你的交易策略需求(如 scalp 策略需要关注微小波动)
  • 进阶建议
    • 收益率标准差 替代价格标准差
    • 结合 ATR(真实波幅) 指标交叉验证
    • 对不同时间段(如亚洲/欧美交易时段)分别计算波动率

这种波动水平意味着,如果你的交易策略目标是捕捉1%以上的波动,可能需要:

  • 改用4小时或日线数据
  • 叠加动量指标(如MACD)过滤信号
  • 增加成交量分析确认突破有效性

在加密货币交易中,方差(Variance)标准差(Standard Deviation)本质上是同一波动性指标的两种表现形式,但方差在实战中有其独特的应用场景和参考价值。以下是针对BTC/USDT交易的详细分析:


1. 方差 vs 标准差的本质关系

指标 公式 单位 特点
方差 $\frac{1}{n}\sum (x_i - \bar{x})^2$ 美元² 放大极端波动的影响
标准差 $\sqrt{\text{方差}}$ 美元 与价格同维度,更直观

2. 方差在BTC交易中的独特价值

(1) 识别异常波动

方差对极端价格波动更敏感,适合检测市场异常:

let prices = vec![50000.0, 50100.0, 49000.0, 52000.0]; // 包含一次暴跌
let variance = prices.variance().unwrap(); // 会显著高于平稳数据
  • 应用场景:当方差突然增大3倍以上,可能预示黑天鹅事件

(2) 波动率聚类分析

加密货币波动往往呈现聚类效应(高波动后继续高波动):

// 计算滚动方差(20小时窗口)
let rolling_var: Vec<_> = prices.windows(20).map(|w| w.variance().unwrap()).collect();

// 检测波动率跃升
if rolling_var.last() > Some(2.0 * rolling_var.mean().unwrap()) {
    println!("⚠️ 波动率聚类出现");
}

(3) 优化止盈策略

方差可帮助设定非对称止盈(根据波动方向调整):

let upside_var = prices.iter().filter(|&&x| x > mean).map(|x| (x - mean).powi(2)).mean();
let downside_var = prices.iter().filter(|&&x| x < mean).map(|x| (x - mean).powi(2)).mean();

// 上涨波动更强时,放宽止盈
let take_profit = if upside_var > downside_var {
    entry_price + 1.8 * std_dev
} else {
    entry_price + 1.2 * std_dev
};

3. 方差与标准差的实战对比

场景 方差更适用 标准差更适用
算法交易 波动率预测模型输入 止损止盈点位计算
风险价值(VaR) 计算极端损失概率 日常风险监控
衍生品定价 期权隐含波动率计算 保证金要求估算
市场状态监测 识别波动率突变(如闪崩预警) 判断当前波动是否正常

4. 具体应用案例

案例1:动态仓位调整

// 波动率越高,仓位越小(使用方差放大极端波动影响)
let risk_adjusted_size = (capital * 0.02) / variance.sqrt(); // 用方差根而非标准差

案例2:趋势强度过滤

// 只有方差 > 历史中位数时才交易
if variance > historical_median_var {
    execute_trend_strategy();
}

案例3:黑天鹅预警系统

// 监测方差与移动平均方差的比率
let var_ratio = variance / rolling_var.mean().unwrap();
if var_ratio > 5.0 {
    trigger_circuit_breaker();
}

5. 为什么你的方差值(3878)合理?

  • 计算示例
    # 假设价格在103,639 ± 62美元波动
    # 方差 ≈ (62)^2 = 3844 ≈ 你的3878
    
  • 市场对比

    资产 1小时方差(美元²) 波动特性
    BTC/USDT 3,000-10,000 高波动
    黄金期货 50-200 低波动
    美股大盘 100-500 中低波动

6. 进阶技巧:方差对数化

对大幅波动的加密货币,可对方差取对数增强数值稳定性:

let log_var = variance.ln(); 
// 用于机器学习模型输入或波动率预测

总结

在BTC/USDT交易中:

  • 标准差:用于日常止损止盈、布林带等直观指标
  • 方差:更适合
    ✅ 量化极端风险
    ✅ 构建波动率预测模型
    ✅ 算法交易的参数优化
    ✅ 市场异常状态检测

建议将二者结合使用:用标准差设定常规止损,用方差监测极端行情并动态调整风控参数。

是的,同一组数据的标准差的平方必定等于方差,这是它们的数学定义决定的。但在实际应用中(尤其是金融数据分析),需要特别注意计算细节和统计假设。以下是具体分析:


1. 数学本质关系

对于同一组数据 [x₁, x₂, ..., xn]

  • 方差 (σ²) = $\frac{1}{n}\sum_{i=1}^n (x_i - \bar{x})^2$
  • 标准差 (σ) = $\sqrt{\text{方差}}$

因此恒有:

let variance = data.variance().unwrap();
let std_dev = data.std_dev().unwrap();
assert!((std_dev.powi(2) - variance).abs() < 1e-10); // 数学上严格相等

2. 实际计算中的注意事项

(1) 样本 vs 总体计算

类型 方差公式 标准差公式 Rust实现
总体 $\frac{1}{n}\sum (x_i - \bar{x})^2$ $\sqrt{\text{总体方差}}$ statrs 默认实现
样本 $\frac{1}{n-1}\sum (x_i - \bar{x})^2$ $\sqrt{\text{样本方差}}$ 需手动调整或使用其他库(如 ndarray-stats
  • 关键区别:分母用 n(总体)还是 n-1(样本无偏估计)
  • 你的案例statrsvariance()std_dev() 使用相同分母,保证平方关系

(2) 浮点数精度误差

let diff = (std_dev.powi(2) - variance).abs();
assert!(diff < 1e-10); // 允许微小浮点误差

(3) 极端值影响

let data = [1.0, 1.0, 1.0, 1.0, 1.0e12]; // 包含极端值
// 方差和标准差都会被极端值显著拉高
// 但依然满足 std_dev² ≈ variance

3. 在BTC价格分析中的验证

用你的实际数据测试:

let prices = [103577.0, 103639.0, 103701.0, ...]; // 你的数据
let var = prices.variance().unwrap();   // 3878.0100643772735
let std = prices.std_dev().unwrap();    // 62.273670715457854

// 验证平方关系
println!("{} == {} ? {}", std.powi(2), var, (std.powi(2) - var).abs() < 1e-10);
// 输出: 3878.010064377274 == 3878.0100643772735 ? true

4. 为什么需要两个指标?

场景 使用方差 使用标准差
数学模型输入 马科维茨投资组合理论 布林带宽度计算
机器学习特征 波动率聚类检测 技术指标可视化
风险价值(VaR) 计算下行风险 设定止损点位
衍生品定价 期权隐含波动率曲面建模 报价波动幅度展示

5. 常见误区

误区1:认为方差比标准差「更精确」

  • 二者包含相同信息,只是单位不同
  • 方差放大极端值影响,适合数学运算;标准差与价格同单位,适合直观理解

误区2:忽略计算方式一致性

// 错误示例:混用总体方差和样本标准差
let var = population_variance(&data); // 用n
let std = sample_std_dev(&data);      // 用n-1
// 此时 std² ≠ var

误区3:对零方差数据未处理

let data = [42.0; 10]; // 所有值相同
assert_eq!(data.variance().unwrap(), 0.0);
assert_eq!(data.std_dev().unwrap(), 0.0);
// 需避免除以零等问题

6. 最佳实践建议

  1. 始终检查计算一致性
    fn verify_variance_std(data: &[f64]) -> bool {
        let var = data.variance().unwrap();
        let std = data.std_dev().unwrap();
        (std.powi(2) - var).abs() < 1e-8
    }
    
  2. 根据场景选择指标
    • 交易信号生成 → 用标准差(直观美元单位)
    • 风险模型构建 → 用方差(便于数学推导)
  3. 对数收益率处理(更适合金融数据):
    let log_returns: Vec<_> = prices.windows(2).map(|w| (w[1]/w[0]).ln()).collect();
    let ret_var = log_returns.variance().unwrap(); // 收益率方差
    

总结

  • 数学关系:对同一组数据,标准差平方必然等于方差(忽略浮点误差)
  • 金融应用:二者相辅相成,方差侧重数学建模,标准差侧重实战交易
  • 你的数据62.273670715457854² ≈ 3878.0100643772735 验证通过
  • 核心建议:在BTC分析中,用标准差设定止损止盈,用方差构建波动率预测模型

在BTC/USDT交易中,statrs的概率分布功能可以深度应用于价格波动建模风险量化交易策略优化。以下是具体应用场景和实战代码示例:


1. 正态分布:价格波动区间预测

假设BTC小时收益率近似正态分布,计算关键价格区间:

use statrs::distribution::{Normal, Continuous};

// 假设历史数据计算得出
let mean_return = 0.001;  // 平均小时收益率 0.1%
let std_dev = 0.005;      // 标准差 0.5%

let normal = Normal::new(mean_return, std_dev).unwrap();

// 计算1小时内收益率落在±1%的概率
let prob = normal.cdf(0.01) - normal.cdf(-0.01);
println!("1小时收益率在±1%内的概率: {:.2}%", prob * 100.0);

应用场景

  • 动态计算支撑/阻力位
  • 评估突破信号的可信度

2. 学生t分布:处理极端波动

加密货币常呈现”肥尾”特性,t分布比正态分布更准确:

use statrs::distribution::StudentsT;

let degrees_of_freedom = 3.0; // 自由度越低,尾部越厚
let t_dist = StudentsT::new(mean_return, std_dev, degrees_of_freedom).unwrap();

// 计算暴跌5%的概率
let crash_prob = 1.0 - t_dist.cdf(-0.05);
println!("1小时暴跌超过5%的概率: {:.4}%", crash_prob * 100.0);

输出示例

1小时暴跌超过5%的概率: 0.37%  # 正态分布可能低估该风险

3. 泊松分布:极端事件预警

预测黑天鹅事件发生频率:

use statrs::distribution::Poisson;

let lambda = 0.2; // 假设每天发生极端波动的平均次数
let poisson = Poisson::new(lambda).unwrap();

// 计算一天内发生≥2次极端波动的概率
let prob = 1.0 - poisson.cdf(1.0); 
println!("单日≥2次极端波动概率: {:.2}%", prob * 100.0);

4. 蒙特卡洛模拟:价格路径预测

use statrs::distribution::Normal;
use rand::distributions::Distribution;

let mut rng = rand::thread_rng();
let normal = Normal::new(mean_return, std_dev).unwrap();

// 模拟未来24小时价格路径
let mut price = 50000.0;
for _ in 0..24 {
    let ret = normal.sample(&mut rng);
    price *= 1.0 + ret;
    println!("模拟价格: {:.2}", price);
}

应用场景

  • 压力测试
  • 期权定价

5. 风险价值(VaR)计算

use statrs::distribution::Normal;

let confidence = 0.95; // 95%置信度
let var = normal.inverse_cdf(1.0 - confidence).abs() * portfolio_value;
println!("1小时95% VaR: ${:.2}", var);

6. 期权策略盈亏分析

用对数正态分布估算期权收益:

use statrs::distribution::LogNormal;

let strike = 55000.0;
let current = 50000.0;
let vol = 0.8; // 年化波动率80%

let ln_dist = LogNormal::new(current.ln(), vol).unwrap();
let call_prob = 1.0 - ln_dist.cdf(strike.ln());

println!("BTC到期价≥{}的概率: {:.2}%", strike, call_prob * 100.0);

关键分布选择指南

分布类型 BTC适用场景 statrs构造方法
正态分布 常规波动区间预测 Normal::new(mean, std_dev)
学生t分布 肥尾风险建模 StudentsT::new(mean, scale, df)
泊松分布 极端事件频率预测 Poisson::new(lambda)
对数正态 期权定价/长期价格预测 LogNormal::new(μ, σ)
伽马分布 交易量爆发模型 Gamma::new(shape, rate)

实战建议

  1. 参数校准
    // 动态更新分布参数
    fn update_distribution(prices: &[f64]) -> Normal {
        let returns = calculate_log_returns(prices);
        let mean = returns.mean().unwrap();
        let std = returns.std_dev().unwrap();
        Normal::new(mean, std).unwrap()
    }
    
  2. 结合多时间框架
    • 短周期(1h):学生t分布
    • 长周期(1d):对数正态分布
  3. 验证分布假设
    use statrs::statistics::Distribution;
    let ks_test = normal.kstest(&observed_data); // Kolmogorov-Smirnov检验
    

statrs的概率分布模块为加密货币交易提供了数学严谨的风险评估工具,尤其适合:

  • 量化回测中的蒙特卡洛模拟
  • 期权策略盈亏概率计算
  • 极端行情预警系统开发