Files
chanlun.rs/chanlun/src/business/synthesizer.rs
T
2026-06-05 09:02:54 +08:00

162 lines
5.5 KiB
Rust

/*
* MIT License
*
* Copyright (c) 2026 YuYuKunKun
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use crate::kline::bar::K线;
use std::collections::HashMap;
/// K线合成器 — 将小周期K线合成为大周期K线
pub struct K线合成器 {
pub 标识: String,
pub 周期组: Vec<i64>,
pub 当前K线: HashMap<i64, Option<K线>>,
pub 合成K线列表: HashMap<i64, Vec<K线>>,
}
impl K线合成器 {
/// 创建K线合成器,按周期升序排列,初始化当前K线和合成K线列表
pub fn new(标识: String, 周期组: Vec<i64>) -> Self {
let mut 周期组 = 周期组;
周期组.sort();
let mut 当前K线 = HashMap::new();
let mut 合成K线列表 = HashMap::new();
for &周期 in &周期组 {
当前K线.insert(周期, None);
合成K线列表.insert(周期, Vec::new());
}
Self {
标识,
周期组,
当前K线,
合成K线列表,
}
}
/// 投喂 — 便捷入口,直接从 OHLCV 创建 K线 并投喂
pub fn 投喂(
&mut self,
时间戳: i64,
: f64,
: f64,
: f64,
: f64,
: f64,
) -> Vec<(i64, K线)> {
let K = K线::创建普K(&self.标识, 时间戳, , , , , , 0, 0);
self.投喂K线(K)
}
/// 投喂K线 — 输入最小周期K线,合成为所有目标周期
/// 返回本次投喂完成了哪些周期的K线(周期 → 完成K线)
pub fn 投喂K线(&mut self, K: K线) -> Vec<(i64, K线)> {
let mut 完成记录 = Vec::new();
let 周期组 = self.周期组.clone();
for 周期 in 周期组 {
if let Some(完成K线) = self._处理单个周期(周期, &K) {
完成记录.push((周期, 完成K线));
}
}
完成记录
}
fn _处理单个周期(&mut self, 周期: i64, K: &K线) -> Option<K线> {
let 目标时间戳 = self._对齐时间戳(K.时间戳, 周期);
let 相同时间 = self.当前K线[&周期]
.as_ref()
.map(|k| k.时间戳 == 目标时间戳)
.unwrap_or(false);
if self.当前K线[&周期].is_none() {
let K线 = self._创建新K线(周期, 目标时间戳, K);
self.当前K线.insert(周期, Some(K线));
None
} else if 相同时间 {
let ent = self.当前K线.get_mut(&周期).unwrap();
Self::_更新K线(ent.as_mut().unwrap(), K);
None
} else {
let 完成K线 = self._完成K线(周期);
let K线 = self._创建新K线(周期, 目标时间戳, K);
self.当前K线.insert(周期, Some(K线));
完成K线
}
}
fn _对齐时间戳(&self, 时间戳: i64, 周期: i64) -> i64 {
if 周期 == 0 {
panic!("_对齐时间戳: 周期不能为0");
}
(时间戳 / 周期) * 周期
}
fn _创建新K线(&self, 周期: i64, 时间戳: i64, K: &K线) -> K线 {
let 序号 = self
.合成K线列表
.get(&周期)
.and_then(|list| list.last())
.map(|k| k.序号 + 1)
.unwrap_or(0);
K线::创建普K(
&self.标识,
时间戳,
K.开盘价,
K.,
K.,
K.收盘价,
K.成交量,
序号,
周期,
)
}
fn _更新K线(当前K线: &mut K线, 新数据: &K线) {
当前K线. = 当前K线..max(新数据.);
当前K线. = 当前K线..min(新数据.);
当前K线.收盘价 = 新数据.收盘价;
当前K线.成交量 += 新数据.成交量;
}
fn _完成K线(&mut self, 周期: i64) -> Option<K线> {
let ent = self.当前K线.get_mut(&周期).unwrap();
let mut k线 = ent.take()?;
k线.序号 = self
.合成K线列表
.get(&周期)
.and_then(|list| list.last())
.map(|k| k.序号 + 1)
.unwrap_or(0);
let 完成K线 = k线.clone();
self.合成K线列表.get_mut(&周期).unwrap().push(k线);
Some(完成K线)
}
/// 获取指定周期当前正在合成的K线
pub fn 获取当前K线(&self, 周期: i64) -> Option<&K线> {
self.当前K线.get(&周期).and_then(|k| k.as_ref())
}
}