246 lines
8.4 KiB
Markdown
246 lines
8.4 KiB
Markdown
|
|
当然可以,RaptorBT 是开源的 Rust 项目,结构很清晰。让我先看看现有指标的实现模式:
|
|||
|
|
The user is asking about modifying the RaptorBT source code to add custom indicators. Let me look at the existing indicator implementation to understand the pattern, then explain how to add a new indicator.
|
|||
|
|
|
|||
|
|
现在看看 `lib.rs` 里的模块注册:
|
|||
|
|
|
|||
|
|
好,现在我对整个代码结构非常清楚了。下面给你完整的说明:
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 添加自定义指标的完整流程
|
|||
|
|
|
|||
|
|
RaptorBT 的指标架构非常清晰,添加一个新指标需要改 **3 个文件**,我以添加 **CCI(Commodity Channel Index)** 为例演示:
|
|||
|
|
|
|||
|
|
### 第 1 步:在 Rust 里实现指标逻辑
|
|||
|
|
|
|||
|
|
在 [momentum.rs](file:///c:/Users/Administrator/Desktop/raptorbt/src/indicators/momentum.rs) 中添加函数(或新建文件都行,这里选 momentum.rs 因为 CCI 属于动量类):
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
/// Commodity Channel Index (CCI).
|
|||
|
|
///
|
|||
|
|
/// # Arguments
|
|||
|
|
/// * `high` - High prices
|
|||
|
|
/// * `low` - Low prices
|
|||
|
|
/// * `close` - Close prices
|
|||
|
|
/// * `period` - Lookback period (default: 20)
|
|||
|
|
///
|
|||
|
|
/// # Returns
|
|||
|
|
/// Vector of CCI values (NaN for warmup period)
|
|||
|
|
pub fn cci(high: &[f64], low: &[f64], close: &[f64], period: usize) -> Result<Vec<f64>> {
|
|||
|
|
if period == 0 {
|
|||
|
|
return Err(RaptorError::invalid_parameter("CCI period must be > 0"));
|
|||
|
|
}
|
|||
|
|
let n = close.len();
|
|||
|
|
if n != high.len() || n != low.len() {
|
|||
|
|
return Err(RaptorError::length_mismatch(n, high.len()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let mut result = vec![f64::NAN; n];
|
|||
|
|
if period >= n {
|
|||
|
|
return Ok(result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Typical Price
|
|||
|
|
let tp: Vec<f64> = (0..n).map(|i| (high[i] + low[i] + close[i]) / 3.0).collect();
|
|||
|
|
|
|||
|
|
// SMA of Typical Price + Mean Deviation
|
|||
|
|
for i in (period - 1)..n {
|
|||
|
|
let start = i + 1 - period;
|
|||
|
|
let tp_sma: f64 = tp[start..=i].iter().sum::<f64>() / period as f64;
|
|||
|
|
let mean_dev: f64 = tp[start..=i].iter().map(|x| (x - tp_sma).abs()).sum::<f64>() / period as f64;
|
|||
|
|
|
|||
|
|
if mean_dev > f64::EPSILON {
|
|||
|
|
result[i] = (tp[i] - tp_sma) / (0.015 * mean_dev);
|
|||
|
|
} else {
|
|||
|
|
result[i] = 0.0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Ok(result)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 第 2 步:在 mod.rs 导出
|
|||
|
|
|
|||
|
|
在 [mod.rs](file:///c:/Users/Administrator/Desktop/raptorbt/src/indicators/mod.rs) 的 `pub use momentum::...` 行加上 `cci`:
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
pub use momentum::{cci, macd, rsi, stochastic, MacdResult, StochasticResult};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 第 3 步:在 bindings.rs 添加 Python 绑定
|
|||
|
|
|
|||
|
|
在 [bindings.rs](file:///c:/Users/Administrator/Desktop/raptorbt/src/python/bindings.rs) 的指标函数区域添加:
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
/// Commodity Channel Index.
|
|||
|
|
#[pyfunction]
|
|||
|
|
pub fn cci<'py>(
|
|||
|
|
py: Python<'py>,
|
|||
|
|
high: PyReadonlyArray1<f64>,
|
|||
|
|
low: PyReadonlyArray1<f64>,
|
|||
|
|
close: PyReadonlyArray1<f64>,
|
|||
|
|
period: usize,
|
|||
|
|
) -> PyResult<&'py PyArray1<f64>> {
|
|||
|
|
let h = numpy_to_vec_f64(high);
|
|||
|
|
let l = numpy_to_vec_f64(low);
|
|||
|
|
let c = numpy_to_vec_f64(close);
|
|||
|
|
let result = indicators::momentum::cci(&h, &l, &c, period)
|
|||
|
|
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
|
|||
|
|
Ok(vec_to_numpy_f64(py, result))
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 第 4 步:在 lib.rs 注册
|
|||
|
|
|
|||
|
|
在 [lib.rs](file:///c:/Users/Administrator/Desktop/raptorbt/src/lib.rs) 的指标注册区添加:
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
m.add_function(wrap_pyfunction!(python::bindings::cci, m)?)?;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 第 5 步:编译 & 使用
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
maturin develop --release
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
然后 Python 里就能用了:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
cci = raptorbt.cci(high, low, close, period=20)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 总结:3 文件修改清单
|
|||
|
|
|
|||
|
|
| 文件 | 改什么 | 位置 |
|
|||
|
|
| ---------------------------------------- | ------------------------------------------------ | ---------------- |
|
|||
|
|
| `src/indicators/momentum.rs`(或新文件) | 实现 `pub fn cci(...) -> Result<Vec<f64>>` | 和 rsi/macd 同级 |
|
|||
|
|
| `src/indicators/mod.rs` | `pub use momentum::cci` | 导出行 |
|
|||
|
|
| `src/python/bindings.rs` | 添加 `#[pyfunction] pub fn cci<...>` | 指标函数区 |
|
|||
|
|
| `src/lib.rs` | `m.add_function(wrap_pyfunction!(...::cci, m)?)` | 指标注册区 |
|
|||
|
|
|
|||
|
|
**规律**:所有现有指标(sma/ema/rsi/macd/atr/bollinger_bands/adx/vwap/supertrend/stochastic/rolling_min/rolling_max)都是这个模式。你照着抄一个最简单的(比如 `sma`),改成自己的计算逻辑就行。
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 添加自定义指标的完整流程
|
|||
|
|
|
|||
|
|
RaptorBT 的指标架构非常清晰,添加一个新指标需要改 **3 个文件**,我以添加 **CCI(Commodity Channel Index)** 为例演示:
|
|||
|
|
|
|||
|
|
### 第 1 步:在 Rust 里实现指标逻辑
|
|||
|
|
|
|||
|
|
在 [momentum.rs](file:///c:/Users/Administrator/Desktop/raptorbt/src/indicators/momentum.rs) 中添加函数(或新建文件都行,这里选 momentum.rs 因为 CCI 属于动量类):
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
/// Commodity Channel Index (CCI).
|
|||
|
|
///
|
|||
|
|
/// # Arguments
|
|||
|
|
/// * `high` - High prices
|
|||
|
|
/// * `low` - Low prices
|
|||
|
|
/// * `close` - Close prices
|
|||
|
|
/// * `period` - Lookback period (default: 20)
|
|||
|
|
///
|
|||
|
|
/// # Returns
|
|||
|
|
/// Vector of CCI values (NaN for warmup period)
|
|||
|
|
pub fn cci(high: &[f64], low: &[f64], close: &[f64], period: usize) -> Result<Vec<f64>> {
|
|||
|
|
if period == 0 {
|
|||
|
|
return Err(RaptorError::invalid_parameter("CCI period must be > 0"));
|
|||
|
|
}
|
|||
|
|
let n = close.len();
|
|||
|
|
if n != high.len() || n != low.len() {
|
|||
|
|
return Err(RaptorError::length_mismatch(n, high.len()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let mut result = vec![f64::NAN; n];
|
|||
|
|
if period >= n {
|
|||
|
|
return Ok(result);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Typical Price
|
|||
|
|
let tp: Vec<f64> = (0..n).map(|i| (high[i] + low[i] + close[i]) / 3.0).collect();
|
|||
|
|
|
|||
|
|
// SMA of Typical Price + Mean Deviation
|
|||
|
|
for i in (period - 1)..n {
|
|||
|
|
let start = i + 1 - period;
|
|||
|
|
let tp_sma: f64 = tp[start..=i].iter().sum::<f64>() / period as f64;
|
|||
|
|
let mean_dev: f64 = tp[start..=i].iter().map(|x| (x - tp_sma).abs()).sum::<f64>() / period as f64;
|
|||
|
|
|
|||
|
|
if mean_dev > f64::EPSILON {
|
|||
|
|
result[i] = (tp[i] - tp_sma) / (0.015 * mean_dev);
|
|||
|
|
} else {
|
|||
|
|
result[i] = 0.0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Ok(result)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 第 2 步:在 mod.rs 导出
|
|||
|
|
|
|||
|
|
在 [mod.rs](file:///c:/Users/Administrator/Desktop/raptorbt/src/indicators/mod.rs) 的 `pub use momentum::...` 行加上 `cci`:
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
pub use momentum::{cci, macd, rsi, stochastic, MacdResult, StochasticResult};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 第 3 步:在 bindings.rs 添加 Python 绑定
|
|||
|
|
|
|||
|
|
在 [bindings.rs](file:///c:/Users/Administrator/Desktop/raptorbt/src/python/bindings.rs) 的指标函数区域添加:
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
/// Commodity Channel Index.
|
|||
|
|
#[pyfunction]
|
|||
|
|
pub fn cci<'py>(
|
|||
|
|
py: Python<'py>,
|
|||
|
|
high: PyReadonlyArray1<f64>,
|
|||
|
|
low: PyReadonlyArray1<f64>,
|
|||
|
|
close: PyReadonlyArray1<f64>,
|
|||
|
|
period: usize,
|
|||
|
|
) -> PyResult<&'py PyArray1<f64>> {
|
|||
|
|
let h = numpy_to_vec_f64(high);
|
|||
|
|
let l = numpy_to_vec_f64(low);
|
|||
|
|
let c = numpy_to_vec_f64(close);
|
|||
|
|
let result = indicators::momentum::cci(&h, &l, &c, period)
|
|||
|
|
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
|
|||
|
|
Ok(vec_to_numpy_f64(py, result))
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 第 4 步:在 lib.rs 注册
|
|||
|
|
|
|||
|
|
在 [lib.rs](file:///c:/Users/Administrator/Desktop/raptorbt/src/lib.rs) 的指标注册区添加:
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
m.add_function(wrap_pyfunction!(python::bindings::cci, m)?)?;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 第 5 步:编译 & 使用
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
maturin develop --release
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
然后 Python 里就能用了:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
cci = raptorbt.cci(high, low, close, period=20)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 总结:3 文件修改清单
|
|||
|
|
|
|||
|
|
| 文件 | 改什么 | 位置 |
|
|||
|
|
| ---------------------------------------- | ------------------------------------------------ | ---------------- |
|
|||
|
|
| `src/indicators/momentum.rs`(或新文件) | 实现 `pub fn cci(...) -> Result<Vec<f64>>` | 和 rsi/macd 同级 |
|
|||
|
|
| `src/indicators/mod.rs` | `pub use momentum::cci` | 导出行 |
|
|||
|
|
| `src/python/bindings.rs` | 添加 `#[pyfunction] pub fn cci<...>` | 指标函数区 |
|
|||
|
|
| `src/lib.rs` | `m.add_function(wrap_pyfunction!(...::cci, m)?)` | 指标注册区 |
|
|||
|
|
|
|||
|
|
**规律**:所有现有指标(sma/ema/rsi/macd/atr/bollinger_bands/adx/vwap/supertrend/stochastic/rolling_min/rolling_max)都是这个模式。你照着抄一个最简单的(比如 `sma`),改成自己的计算逻辑就行。
|