1use serde_derive::*;
2use serde::Deserialize;
3use jqdata_derive::*;
4use bigdecimal::BigDecimal;
5use std::io::Read;
6use crate::{Result, Error};
7
8#[derive(Debug, Serialize, Deserialize)]
16pub struct Request<P> {
17 token: String,
18 method: String,
19 #[serde(flatten)]
20 payload: P,
21}
22
23pub trait HasMethod {
26 fn method(&self) -> String;
27}
28
29impl<P: HasMethod> Request<P> {
30 pub fn new(token: String, payload: P) -> Self {
31 Request{
32 token,
33 method: payload.method(),
34 payload,
35 }
36 }
37}
38
39pub trait BodyConsumer<T>
42where for<'de> T: Deserialize<'de>
43{
44 fn consume_body<R: Read>(body: R) -> Result<T>;
45}
46
47pub trait CsvListBodyConsumer {
50 type Output: for<'de> Deserialize<'de>;
51
52 fn consume<R: Read>(body: R) -> Result<Vec<Self::Output>> {
53 let mut reader = csv::ReaderBuilder::new()
54 .from_reader(body);
56 let header_cols: Vec<&str> = reader.headers()?.into_iter().collect();
58 if header_cols.is_empty() {
59 return Err(Error::Server("empty response body returned".to_owned()));
60 }
61 let first_col = header_cols.first().cloned().unwrap();
62 if first_col.starts_with("error") {
63 return Err(Error::Server(first_col.to_owned()));
64 }
65 let mut rs = Vec::new();
66 for r in reader.deserialize() {
67 let s: Self::Output = r?;
68 rs.push(s);
69 }
70 Ok(rs)
71 }
72}
73
74pub trait LineBodyConsumer {
77 fn consume<R: Read>(body: R) -> Result<Vec<String>> {
78 use std::io::BufRead;
79 let reader = std::io::BufReader::new(body);
80 let mut rs = Vec::new();
81 for line in reader.lines() {
82 rs.push(line?);
83 }
84 Ok(rs)
85 }
86}
87
88pub trait SingleBodyConsumer<T> where T: std::str::FromStr, Error: From<T::Err> {
91 fn consume<R: Read>(body: R) -> Result<T> {
92 let mut body = body;
93 let mut vec = Vec::new();
94 std::io::copy(&mut body, &mut vec)?;
95 let s = String::from_utf8(vec)?;
96 let result = s.parse()?;
97 Ok(result)
98 }
99}
100
101pub trait JsonBodyConsumer {
104 type Output: for<'de> Deserialize<'de>;
105
106 fn consume<R: Read>(body: R) -> Result<Self::Output> {
107 let result = serde_json::from_reader(body)?;
108 Ok(result)
109 }
110}
111
112#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
114#[serde(rename_all = "snake_case")]
115pub enum SecurityKind {
116 Stock,
117 Fund,
118 Index,
119 Futures,
120 #[serde(rename = "etf")]
121 ETF,
122 #[serde(rename = "lof")]
123 LOF,
124 #[serde(rename = "fja")]
125 FJA,
126 #[serde(rename = "fjb")]
127 FJB,
128 #[serde(rename = "QDII_fund")]
129 QDIIFund,
130 OpenFund,
131 BondFund,
132 StockFund,
133 MoneyMarketFund,
134 MixtureFund,
135 Options,
136}
137
138#[derive(Debug, Serialize, Deserialize, PartialEq)]
140pub struct Security {
141 pub code: String,
142 pub display_name: String,
143 pub name: String,
144 pub start_date: String,
145 pub end_date: String,
146 #[serde(rename = "type")]
147 pub kind: SecurityKind,
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub parent: Option<String>,
150}
151
152#[derive(Debug, Serialize, Deserialize, Jqdata)]
154#[method("get_all_securities")]
155#[consume(format = "csv", type = "Security")]
156pub struct GetAllSecurities {
157 pub code: SecurityKind,
158 #[serde(skip_serializing_if = "Option::is_none")]
159 pub date: Option<String>,
160}
161
162#[derive(Debug, Serialize, Deserialize, Jqdata)]
164#[method("get_security_info")]
165#[consume(format = "csv", type = "Security")]
166pub struct GetSecurityInfo {
167 pub code: String,
168}
169
170#[derive(Debug, Serialize, Deserialize, Jqdata)]
172#[method("get_index_stocks")]
173#[consume(format = "line")]
174pub struct GetIndexStocks {
175 pub code: String,
176 pub date: String,
177}
178
179#[derive(Debug, Serialize, Deserialize, Jqdata)]
182#[method("get_margincash_stocks")]
183#[consume(format = "line")]
184pub struct GetMargincashStocks {
185 #[serde(skip_serializing_if = "Option::is_none")]
186 pub date: Option<String>,
187}
188
189#[derive(Debug, Serialize, Deserialize, Jqdata)]
191#[method("get_locked_shares")]
192#[consume(format = "csv", type = "LockedShare")]
193pub struct GetLockedShares {
194 pub code: String,
195 pub date: String,
196 pub end_date: String,
197}
198
199#[derive(Debug, Serialize, Deserialize)]
200pub struct LockedShare {
201 pub day: String,
202 pub code: String,
203 pub num: BigDecimal,
204 pub rate1: BigDecimal,
205 pub rate2: BigDecimal,
206}
207
208#[derive(Debug, Serialize, Deserialize, Jqdata)]
212#[method("get_index_weights")]
213#[consume(format = "csv", type = "IndexWeight")]
214pub struct GetIndexWeights {
215 pub code: String,
216 pub date: String,
217}
218
219#[derive(Debug, Serialize, Deserialize)]
220pub struct IndexWeight {
221 pub code: String,
222 pub display_name: String,
223 pub date: String,
224 pub weight: BigDecimal,
225}
226
227#[derive(Debug, Serialize, Deserialize, Jqdata)]
236#[method("get_industries")]
237#[consume(format = "csv", type = "IndustryIndex")]
238pub struct GetIndustries {
239 pub code: String,
240}
241
242#[derive(Debug, Serialize, Deserialize)]
243pub struct IndustryIndex {
244 pub index: String,
245 pub name: String,
246 pub start_date: String,
247}
248
249#[derive(Debug, Serialize, Deserialize, Jqdata)]
254#[method("get_industry")]
255#[consume(format = "csv", type = "Industry")]
256pub struct GetIndustry {
257 pub code: String,
258 pub date: String,
259}
260
261#[derive(Debug, Serialize, Deserialize)]
262pub struct Industry {
263 pub industry: String,
264 pub industry_code: String,
265 pub industry_name: String,
266}
267
268#[derive(Debug, Serialize, Deserialize, Jqdata)]
273#[method("get_industry_stocks")]
274#[consume(format = "line")]
275pub struct GetIndustryStocks {
276 pub code: String,
277 pub date: String,
278}
279
280#[derive(Debug, Serialize, Deserialize, Jqdata)]
285#[method("get_concepts")]
286#[consume(format = "csv", type = "Concept")]
287pub struct GetConcepts {}
288
289#[derive(Debug, Serialize, Deserialize)]
290pub struct Concept {
291 pub code: String,
292 pub name: String,
293 pub start_date: String,
294}
295
296#[derive(Debug, Serialize, Deserialize, Jqdata)]
301#[method("get_concept_stocks")]
302#[consume(format = "line")]
303pub struct GetConceptStocks {
304 pub code: String,
305 pub date: String,
306}
307
308#[derive(Debug, Serialize, Deserialize, Jqdata)]
313#[method("get_trade_days")]
314#[consume(format = "line")]
315pub struct GetTradeDays {
316 pub date: String,
317 #[serde(skip_serializing_if = "Option::is_none")]
318 pub end_date: Option<String>,
319}
320
321#[derive(Debug, Serialize, Deserialize, Jqdata)]
323#[method("get_all_trade_days")]
324#[consume(format = "line")]
325pub struct GetAllTradeDays {}
326
327#[derive(Debug, Serialize, Deserialize, Jqdata)]
343#[method("get_mtss")]
344#[consume(format = "csv", type = "Mtss")]
345pub struct GetMtss {
346 pub code: String,
347 pub date: String,
348 pub end_date: String,
349}
350
351#[derive(Debug, Serialize, Deserialize)]
352pub struct Mtss {
353 pub date: String,
354 pub sec_code: String,
355 pub fin_value: BigDecimal,
356 pub fin_refund_value: BigDecimal,
357 pub sec_value: BigDecimal,
358 pub sec_sell_value: BigDecimal,
359 pub sec_refund_value: BigDecimal,
360 pub fin_sec_value: BigDecimal,
361}
362
363#[derive(Debug, Serialize, Deserialize, Jqdata)]
383#[method("get_money_flow")]
384#[consume(format = "csv", type = "MoneyFlow")]
385pub struct GetMoneyFlow {
386 pub code: String,
387 pub date: String,
388 pub end_date: String,
389}
390
391#[derive(Debug, Serialize, Deserialize)]
392pub struct MoneyFlow {
393 pub date: String,
394 pub sec_code: String,
395 pub change_pct: BigDecimal,
396 pub net_amount_main: BigDecimal,
397 pub net_pct_main: BigDecimal,
398 pub net_amount_xl: BigDecimal,
399 pub net_pct_xl: BigDecimal,
400 pub net_amount_l: BigDecimal,
401 pub net_pct_l: BigDecimal,
402 pub net_amount_m: BigDecimal,
403 pub net_pct_m: BigDecimal,
404 pub net_amount_s: BigDecimal,
405 pub net_pct_s: BigDecimal,
406}
407
408#[derive(Debug, Serialize, Deserialize, Jqdata)]
428#[method("get_billboard_list")]
429#[consume(format = "csv", type = "BillboardStock")]
430pub struct GetBillboardList {
431 pub code: String,
432 pub date: String,
433 pub end_date: String,
434}
435
436#[derive(Debug, Serialize, Deserialize)]
437pub struct BillboardStock {
438 pub code: String,
439 pub day: String,
440 pub direction: String,
441 pub rank: i32,
442 pub abnormal_code: String,
443 pub abnormal_name: String,
444 pub sales_depart_name: String,
445 pub buy_value: BigDecimal,
446 pub buy_rate: BigDecimal,
447 pub sell_value: BigDecimal,
448 pub sell_rate: BigDecimal,
449 pub total_value: BigDecimal,
450 pub net_value: BigDecimal,
451 pub amount: BigDecimal,
452}
453
454#[derive(Debug, Serialize, Deserialize, Jqdata)]
459#[method("get_future_contracts")]
460#[consume(format = "line")]
461pub struct GetFutureContracts {
462 pub code: String,
463 pub date: String,
464}
465
466#[derive(Debug, Serialize, Deserialize, Jqdata)]
471#[method("get_dominant_future")]
472#[consume(format = "line")]
473pub struct GetDominantFuture {
474 pub code: String,
475 pub date: String,
476}
477
478#[derive(Debug, Serialize, Deserialize, Jqdata)]
498#[method("get_fund_info")]
499#[consume(format = "json", type = "FundInfo")]
500pub struct GetFundInfo {
501 pub code: String,
502 pub date: String,
503}
504
505#[derive(Debug, Serialize, Deserialize)]
506pub struct FundInfo {
507 pub fund_name: String,
508 pub fund_type: String,
509 pub fund_establishment_day: String,
510 pub fund_manager: String,
511 pub fund_management_fee: String,
512 pub fund_custodian_fee: String,
513 pub fund_status: String,
514 pub fund_size: String,
515 pub fund_share: BigDecimal,
516 pub fund_asset_allocation_proportion: String,
517 pub heavy_hold_stocks: Vec<String>,
518 pub heavy_hold_stocks_proportion: BigDecimal,
519 pub heavy_hold_bond: Vec<String>,
520 pub heavy_hold_bond_proportion: BigDecimal,
521}
522
523#[derive(Debug, Serialize, Deserialize, Jqdata)]
539#[method("get_current_tick")]
540#[consume(format = "csv", type = "Tick")]
541pub struct GetCurrentTick {
542 pub code: String,
543}
544
545#[derive(Debug, Serialize, Deserialize)]
546pub struct Tick {
547 pub time: BigDecimal,
548 pub current: BigDecimal,
549 pub high: BigDecimal,
550 pub low: BigDecimal,
551 pub volumn: BigDecimal,
552 pub money: BigDecimal,
553 pub position: BigDecimal,
554 pub a1_v: BigDecimal,
555 pub a2_v: BigDecimal,
556 pub a3_v: BigDecimal,
557 pub a4_v: BigDecimal,
558 pub a5_v: BigDecimal,
559 pub a1_p: BigDecimal,
560 pub a2_p: BigDecimal,
561 pub a3_p: BigDecimal,
562 pub a4_p: BigDecimal,
563 pub a5_p: BigDecimal,
564 pub b1_v: BigDecimal,
565 pub b2_v: BigDecimal,
566 pub b3_v: BigDecimal,
567 pub b4_v: BigDecimal,
568 pub b5_v: BigDecimal,
569 pub b1_p: BigDecimal,
570 pub b2_p: BigDecimal,
571 pub b3_p: BigDecimal,
572 pub b4_p: BigDecimal,
573 pub b5_p: BigDecimal,
574}
575
576#[derive(Debug, Serialize, Deserialize, Jqdata)]
580#[method("get_current_ticks")]
581#[consume(format = "csv", type = "Tick")]
582pub struct GetCurrentTicks {
583 pub code: String,
584}
585
586#[derive(Debug, Serialize, Deserialize, Jqdata)]
600#[method("get_extras")]
601#[consume(format = "csv", type = "Extra")]
602pub struct GetExtras {
603 pub code: String,
604 pub date: String,
605 pub end_date: String,
606}
607
608#[derive(Debug, Serialize, Deserialize)]
609pub struct Extra {
610 pub date: String,
611 pub is_st: Option<i8>,
612 pub acc_net_value: Option<f64>,
613 pub unit_net_value: Option<f64>,
614 pub futures_sett_price: Option<f64>,
615 pub futures_positions: Option<f64>,
616 pub adj_net_value: Option<f64>,
617}
618
619#[derive(Debug, Serialize, Deserialize, Jqdata)]
643#[method("get_price")]
644#[consume(format = "csv", type = "Price")]
645pub struct GetPrice {
646 pub date: String,
647 pub count: u32,
648 pub unit: String,
649 #[serde(skip_serializing_if = "Option::is_none")]
650 pub end_date: Option<String>,
651 #[serde(skip_serializing_if = "Option::is_none")]
652 pub fq_ref_date: Option<String>,
653}
654
655#[derive(Debug, Serialize, Deserialize)]
656pub struct Price {
657 pub date: String,
658 pub open: BigDecimal,
659 pub close: BigDecimal,
660 pub high: BigDecimal,
661 pub low: BigDecimal,
662 pub volume: BigDecimal,
663 pub money: BigDecimal,
664 pub paused: Option<u8>,
665 pub high_limit: Option<f64>,
666 pub low_limit: Option<f64>,
667 pub avg: Option<f64>,
668 pub pre_close: Option<f64>,
669 pub open_interest: Option<f64>,
670}
671
672#[derive(Debug, Serialize, Deserialize, Jqdata)]
696#[method("get_price_period")]
697#[consume(format = "csv", type = "Price")]
698pub struct GetPricePeriod {
699 pub code: String,
700 pub unit: String,
701 pub date: String,
702 pub end_date: String,
703 #[serde(skip_serializing_if = "Option::is_none")]
704 pub fq_ref_date: Option<String>,
705}
706
707#[derive(Debug, Serialize, Deserialize, Jqdata)]
719#[method("get_ticks")]
720#[consume(format = "csv", type = "Tick")]
721pub struct GetTicks {
722 pub code: String,
723 #[serde(skip_serializing_if = "Option::is_none")]
724 pub count: Option<u32>,
725 pub end_date: String,
726 pub skip: bool,
727}
728
729#[derive(Debug, Serialize, Deserialize, Jqdata)]
742#[method("get_ticks_period")]
743#[consume(format = "csv", type = "Tick")]
744pub struct GetTicksPeriod {
745 pub code: String,
746 pub date: String,
747 pub end_date: String,
748 pub skip: bool,
749}
750
751#[derive(Debug, Serialize, Deserialize, Jqdata)]
765#[method("get_factor_values")]
766#[consume(format = "csv", type = "FactorValue")]
767pub struct GetFactorValues {
768 pub code: String,
769 pub columns: String,
770 pub date: String,
771 pub end_date: String,
772}
773
774#[derive(Debug, Serialize, Deserialize)]
775pub struct FactorValue {
776 pub date: String,
777 pub cfo_to_ev: Option<f64>,
778 pub net_profit_ratio: Option<f64>,
779}
780
781#[derive(Debug, Serialize, Deserialize, Jqdata)]
791#[method(run_query)]
792#[consume(format = "line")]
793pub struct RunQuery {
794 pub table: String,
795 pub columns: String,
796 #[serde(skip_serializing_if = "Option::is_none")]
797 pub conditions: Option<String>,
798 #[serde(skip_serializing_if = "Option::is_none")]
799 pub count: Option<u32>,
800}
801
802#[derive(Debug, Serialize, Deserialize, Jqdata)]
804#[method("get_query_count")]
805#[consume(format = "single", type = "i32")]
806pub struct GetQueryCount {}