1use futu_core::error::{FutuError, Result};
2use futu_core::proto_id;
3use futu_net::client::FutuClient;
4
5use crate::subscription_plan::SESSION_OVERNIGHT;
6use crate::types::{KLType, KLine, RehabType, Security};
7
8#[derive(Debug, Clone)]
10pub struct HistoryKLResult {
11 pub security: Security,
12 pub kl_list: Vec<KLine>,
13 pub next_kl_time: Option<String>,
15 pub next_req_key: Option<Vec<u8>>,
17}
18
19#[derive(Debug, Clone, Copy, Default)]
21pub struct HistoryKLOptions<'a> {
22 pub need_kl_fields_flag: Option<i64>,
24 pub next_req_key: Option<&'a [u8]>,
26 pub extended_time: Option<bool>,
28 pub session: Option<i32>,
30}
31
32pub async fn get_history_kl(
39 client: &FutuClient,
40 security: &Security,
41 rehab_type: RehabType,
42 kl_type: KLType,
43 begin_time: &str,
44 end_time: &str,
45 max_num: Option<i32>,
46) -> Result<HistoryKLResult> {
47 get_history_kl_with_options(
48 client,
49 security,
50 rehab_type,
51 kl_type,
52 begin_time,
53 end_time,
54 max_num,
55 HistoryKLOptions::default(),
56 )
57 .await
58}
59
60pub async fn get_history_kl_with_options(
62 client: &FutuClient,
63 security: &Security,
64 rehab_type: RehabType,
65 kl_type: KLType,
66 begin_time: &str,
67 end_time: &str,
68 max_num: Option<i32>,
69 options: HistoryKLOptions<'_>,
70) -> Result<HistoryKLResult> {
71 let result = request_history_kl(
72 client,
73 &RequestHistoryKLParams {
74 security,
75 rehab_type,
76 kl_type,
77 begin_time,
78 end_time,
79 max_num,
80 need_kl_fields_flag: options.need_kl_fields_flag,
81 next_req_key: options.next_req_key,
82 extended_time: options.extended_time,
83 session: options.session,
84 },
85 )
86 .await?;
87
88 Ok(HistoryKLResult {
89 security: result.security,
90 kl_list: result.kl_list,
91 next_kl_time: None, next_req_key: result.next_req_key,
93 })
94}
95
96#[derive(Debug, Clone)]
98pub struct RequestHistoryKLParams<'a> {
99 pub security: &'a Security,
100 pub rehab_type: RehabType,
101 pub kl_type: KLType,
102 pub begin_time: &'a str,
103 pub end_time: &'a str,
104 pub max_num: Option<i32>,
105 pub need_kl_fields_flag: Option<i64>,
106 pub next_req_key: Option<&'a [u8]>,
107 pub extended_time: Option<bool>,
108 pub session: Option<i32>,
109}
110
111#[derive(Debug, Clone)]
113pub struct RequestHistoryKLResult {
114 pub security: Security,
115 pub kl_list: Vec<KLine>,
116 pub next_req_key: Option<Vec<u8>>,
118}
119
120pub async fn request_history_kl(
122 client: &FutuClient,
123 params: &RequestHistoryKLParams<'_>,
124) -> Result<RequestHistoryKLResult> {
125 validate_history_kline_session(params.session)?;
126
127 let req = futu_proto::qot_request_history_kl::Request {
128 c2s: futu_proto::qot_request_history_kl::C2s {
129 rehab_type: params.rehab_type as i32,
130 kl_type: params.kl_type as i32,
131 security: params.security.to_proto(),
132 begin_time: params.begin_time.to_string(),
133 end_time: params.end_time.to_string(),
134 max_ack_kl_num: params.max_num,
135 need_kl_fields_flag: params.need_kl_fields_flag,
136 next_req_key: params.next_req_key.map(|k| k.to_vec()),
137 extended_time: params.extended_time,
138 session: params.session,
139 header: None,
140 },
141 };
142
143 let body = prost::Message::encode_to_vec(&req);
144 let resp_frame = client
145 .request(proto_id::QOT_REQUEST_HISTORY_KL, body)
146 .await?;
147
148 let resp: futu_proto::qot_request_history_kl::Response =
149 prost::Message::decode(resp_frame.body.as_ref()).map_err(FutuError::Proto)?;
150
151 if resp.ret_type != 0 {
152 return Err(crate::server_err(resp.ret_type, resp.ret_msg));
153 }
154
155 let s2c = resp
156 .s2c
157 .ok_or(FutuError::Codec("missing s2c in RequestHistoryKL".into()))?;
158
159 Ok(RequestHistoryKLResult {
160 security: Security::from_proto(&s2c.security),
161 kl_list: s2c.kl_list.iter().map(KLine::from_proto).collect(),
162 next_req_key: s2c.next_req_key,
163 })
164}
165
166fn validate_history_kline_session(session: Option<i32>) -> Result<()> {
167 if session == Some(SESSION_OVERNIGHT) {
168 return Err(FutuError::Codec(
169 "RequestHistoryKL: session=OVERNIGHT (4) is not supported".into(),
170 ));
171 }
172 Ok(())
173}
174
175#[cfg(test)]
176mod tests;