futu_cache/
static_data.rs

1// 静态数据缓存:股票列表、经纪商、节假日、停牌
2
3use dashmap::DashMap;
4use std::sync::RwLock;
5
6/// 股票静态信息
7#[derive(Debug, Clone)]
8pub struct CachedSecurityInfo {
9    pub stock_id: u64,
10    pub market: i32,
11    pub code: String,
12    pub name: String,
13    pub lot_size: i32,
14    pub sec_type: i32,
15    pub list_time: String,
16    /// 窝轮所属正股 ID, 0 表示无
17    pub warrnt_stock_owner: u64,
18    /// 是否已退市
19    pub delisting: bool,
20    /// 交易所类型 (ExchType)
21    pub exch_type: i32,
22    /// 不可搜索标记 (对齐 C++ no_search 字段)
23    pub no_search: bool,
24}
25
26/// 交易日
27#[derive(Debug, Clone)]
28pub struct CachedTradeDate {
29    pub time: String,
30    pub timestamp: f64,
31}
32
33/// 板块信息
34#[derive(Debug, Clone)]
35pub struct CachedPlateInfo {
36    pub market: i32,
37    pub code: String,
38    pub name: String,
39    pub plate_type: i32,
40}
41
42/// 静态数据缓存
43pub struct StaticDataCache {
44    /// 股票静态信息: "market_code" → info
45    pub securities: DashMap<String, CachedSecurityInfo>,
46    /// stock_id → "market_code" key (反向映射,用于推送时查找)
47    pub id_to_key: DashMap<u64, String>,
48    /// 交易日: "market:year-month" → Vec<TradeDate>
49    pub trade_dates: DashMap<String, Vec<CachedTradeDate>>,
50    /// 板块: "market:plate_type" → Vec<PlateInfo>
51    pub plates: DashMap<String, Vec<CachedPlateInfo>>,
52    /// 窝轮正股 owner_id → 该正股对应的所有窝轮 stock_id 列表
53    /// 用于 GetReference(Warrant) 查询
54    pub owner_to_warrants: RwLock<std::collections::HashMap<u64, Vec<u64>>>,
55}
56
57impl StaticDataCache {
58    pub fn new() -> Self {
59        Self {
60            securities: DashMap::new(),
61            id_to_key: DashMap::new(),
62            trade_dates: DashMap::new(),
63            plates: DashMap::new(),
64            owner_to_warrants: RwLock::new(std::collections::HashMap::new()),
65        }
66    }
67
68    pub fn set_security_info(&self, key: &str, info: CachedSecurityInfo) {
69        self.securities.insert(key.to_string(), info);
70    }
71
72    pub fn get_security_info(&self, key: &str) -> Option<CachedSecurityInfo> {
73        self.securities.get(key).map(|v| v.clone())
74    }
75
76    /// 通过 stock_id 查找股票信息 (使用 id_to_key 反向映射)
77    pub fn get_security_info_by_stock_id(&self, stock_id: u64) -> Option<CachedSecurityInfo> {
78        let key = self.id_to_key.get(&stock_id)?;
79        self.securities.get(key.value().as_str()).map(|v| v.clone())
80    }
81
82    /// 添加窝轮→正股的映射关系
83    pub fn add_warrant_owner(&self, warrant_stock_id: u64, owner_stock_id: u64) {
84        if owner_stock_id == 0 {
85            return;
86        }
87        if let Ok(mut map) = self.owner_to_warrants.write() {
88            map.entry(owner_stock_id)
89                .or_default()
90                .push(warrant_stock_id);
91        }
92    }
93
94    /// 通过正股 ID 搜索该正股的所有窝轮
95    pub fn search_warrants_by_owner(&self, owner_stock_id: u64) -> Vec<u64> {
96        if let Ok(map) = self.owner_to_warrants.read() {
97            map.get(&owner_stock_id).cloned().unwrap_or_default()
98        } else {
99            Vec::new()
100        }
101    }
102}
103
104impl Default for StaticDataCache {
105    fn default() -> Self {
106        Self::new()
107    }
108}