jqdata_blocking/
model.rs

1use crate::error::Error;
2use jqdata_derive::*;
3#[allow(unused_imports)]
4use serde::{Deserialize, Serialize};
5#[allow(unused_imports)]
6use serde_derive::*;
7use std::io::BufRead;
8use std::str::FromStr;
9
10/// Request
11///
12/// define how to generate request body
13pub trait Request {
14    // generate request body, with given token
15    fn request(&self, token: &str) -> Result<String, Error>;
16}
17
18/// Response
19///
20/// defines how to handle response body
21pub trait Response {
22    type Output;
23    // response is consumed, and the parsed output is returned
24    fn response(&self, response: reqwest::blocking::Response) -> Result<Self::Output, Error>;
25}
26
27// csv consuming function, used by derive macro
28#[allow(dead_code)]
29pub(crate) fn consume_csv<T>(response: &mut reqwest::blocking::Response) -> Result<Vec<T>, Error>
30where
31    for<'de> T: Deserialize<'de>,
32{
33    let mut reader = csv::ReaderBuilder::new()
34        // .has_headers(true)
35        .from_reader(response);
36    // consume the first row as header
37    let header_cols: Vec<&str> = reader.headers()?.into_iter().collect();
38    if header_cols.is_empty() {
39        return Err(Error::Server("empty response body returned".to_owned()));
40    }
41    let first_col = header_cols.first().cloned().unwrap();
42    if first_col.starts_with("error") {
43        return Err(Error::Server(first_col.to_owned()));
44    }
45    let mut rs = Vec::new();
46    for r in reader.deserialize() {
47        let s: T = r?;
48        rs.push(s);
49    }
50    Ok(rs)
51}
52
53// line consuming function, used by derive macro
54#[allow(dead_code)]
55pub(crate) fn consume_line(
56    response: &mut reqwest::blocking::Response,
57) -> Result<Vec<String>, Error> {
58    let reader = std::io::BufReader::new(response);
59    let mut rs = Vec::new();
60    for line in reader.lines() {
61        rs.push(line?);
62    }
63    Ok(rs)
64}
65
66// single result consuming function, used by derive macro
67pub(crate) fn consume_single<T>(response: &mut reqwest::blocking::Response) -> Result<T, Error>
68where
69    T: FromStr,
70    Error: From<T::Err>,
71{
72    let mut vec = Vec::new();
73    std::io::copy(response, &mut vec)?;
74    let s = String::from_utf8(vec)?;
75    let result = s.parse::<T>()?;
76    Ok(result)
77}
78
79// json consuming function, used by derive macro
80#[allow(dead_code)]
81pub(crate) fn consume_json<T>(response: &mut reqwest::blocking::Response) -> Result<T, Error>
82where
83    for<'de> T: Deserialize<'de>,
84{
85    let result = serde_json::from_reader(response)?;
86    Ok(result)
87}
88
89/// 证券类型
90#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
91#[serde(rename_all = "snake_case")]
92pub enum SecurityKind {
93    Stock,
94    Fund,
95    Index,
96    Futures,
97    #[serde(rename = "etf")]
98    ETF,
99    #[serde(rename = "lof")]
100    LOF,
101    #[serde(rename = "fja")]
102    FJA,
103    #[serde(rename = "fjb")]
104    FJB,
105    #[serde(rename = "QDII_fund")]
106    QDIIFund,
107    OpenFund,
108    BondFund,
109    StockFund,
110    MoneyMarketFund,
111    MixtureFund,
112    Options,
113}
114
115/// 证券信息
116#[derive(Debug, Serialize, Deserialize, PartialEq)]
117pub struct Security {
118    pub code: String,
119    pub display_name: String,
120    pub name: String,
121    pub start_date: String,
122    pub end_date: String,
123    #[serde(rename = "type")]
124    pub kind: SecurityKind,
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub parent: Option<String>,
127}
128
129/// all requests are defined below
130
131/// 获取平台支持的所有股票、基金、指数、期货信息
132#[derive(Debug, Serialize, Deserialize, Request, Response)]
133#[request(get_all_securities)]
134#[response(format = "csv", type = "Security")]
135pub struct GetAllSecurities {
136    pub code: SecurityKind,
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub date: Option<String>,
139}
140
141/// 获取股票/基金/指数的信息
142#[derive(Debug, Serialize, Deserialize, Request, Response)]
143#[request(get_security_info)]
144#[response(format = "csv", type = "Security")]
145pub struct GetSecurityInfo {
146    pub code: String,
147}
148
149/// 获取一个指数给定日期在平台可交易的成分股列表
150#[derive(Debug, Serialize, Deserialize, Request, Response)]
151#[request(get_index_stocks)]
152#[response(format = "line")]
153pub struct GetIndexStocks {
154    pub code: String,
155    pub date: String,
156}
157
158/// 获取指定日期上交所、深交所披露的的可融资标的列表
159/// 查询日期,默认为前一交易日
160#[derive(Debug, Serialize, Deserialize, Request, Response)]
161#[request(get_margincash_stocks)]
162#[response(format = "line")]
163pub struct GetMargincashStocks {
164    #[serde(skip_serializing_if = "Option::is_none")]
165    pub date: Option<String>,
166}
167
168/// 获取指定日期区间内的限售解禁数据
169#[derive(Debug, Serialize, Deserialize, Request, Response)]
170#[request(get_locked_shares)]
171#[response(format = "csv", type = "LockedShare")]
172pub struct GetLockedShares {
173    pub code: String,
174    pub date: String,
175    pub end_date: String,
176}
177
178#[derive(Debug, Serialize, Deserialize)]
179pub struct LockedShare {
180    pub day: String,
181    pub code: String,
182    pub num: f64,
183    pub rate1: f64,
184    pub rate2: f64,
185}
186
187/// 获取指数成份股给定日期的权重数据,每月更新一次
188/// code: 代表指数的标准形式代码, 形式:指数代码.交易所代码,例如"000001.XSHG"。
189/// date: 查询权重信息的日期,形式:"%Y-%m-%d",例如"2018-05-03";
190#[derive(Debug, Serialize, Deserialize, Request, Response)]
191#[request(get_index_weights)]
192#[response(format = "csv", type = "IndexWeight")]
193pub struct GetIndexWeights {
194    pub code: String,
195    pub date: String,
196}
197
198#[derive(Debug, Serialize, Deserialize)]
199pub struct IndexWeight {
200    pub code: String,
201    pub display_name: String,
202    pub date: String,
203    pub weight: f64,
204}
205
206/// 按照行业分类获取行业列表
207/// code:行业代码
208/// sw_l1: 申万一级行业
209/// sw_l2: 申万二级行业
210/// sw_l3: 申万三级行业
211/// jq_l1: 聚宽一级行业
212/// jq_l2: 聚宽二级行业
213/// zjw: 证监会行业
214#[derive(Debug, Serialize, Deserialize, Request, Response)]
215#[request(get_industries)]
216#[response(format = "csv", type = "IndustryIndex")]
217pub struct GetIndustries {
218    pub code: String,
219}
220
221#[derive(Debug, Serialize, Deserialize)]
222pub struct IndustryIndex {
223    pub index: String,
224    pub name: String,
225    pub start_date: String,
226}
227
228/// 查询股票所属行业
229/// 参数:
230/// code:证券代码
231/// date:查询的日期
232#[derive(Debug, Serialize, Deserialize, Request, Response)]
233#[request(get_industry)]
234#[response(format = "csv", type = "Industry")]
235pub struct GetIndustry {
236    pub code: String,
237    pub date: String,
238}
239
240#[derive(Debug, Serialize, Deserialize)]
241pub struct Industry {
242    pub industry: String,
243    pub industry_code: String,
244    pub industry_name: String,
245}
246
247/// 获取在给定日期一个行业的所有股票
248/// 参数:
249/// code: 行业编码
250/// date: 查询日期
251#[derive(Debug, Serialize, Deserialize, Request, Response)]
252#[request(get_industry_stocks)]
253#[response(format = "line")]
254pub struct GetIndustryStocks {
255    pub code: String,
256    pub date: String,
257}
258
259/// 获取在给定日期一个概念板块的所有股票
260/// 参数:
261/// code: 概念板块编码
262/// date: 查询日期,
263#[derive(Debug, Serialize, Deserialize, Request, Response)]
264#[request(get_concepts)]
265#[response(format = "csv", type = "Concept")]
266pub struct GetConcepts {}
267
268#[derive(Debug, Serialize, Deserialize)]
269pub struct Concept {
270    pub code: String,
271    pub name: String,
272    pub start_date: String,
273}
274
275/// 获取在给定日期一个概念板块的所有股票
276/// 参数:
277/// code: 概念板块编码
278/// date: 查询日期,
279#[derive(Debug, Serialize, Deserialize, Request, Response)]
280#[request(get_concept_stocks)]
281#[response(format = "line")]
282pub struct GetConceptStocks {
283    pub code: String,
284    pub date: String,
285}
286
287/// 获取指定日期范围内的所有交易日
288/// 参数:
289/// date: 开始日期
290/// end_date: 结束日期
291#[derive(Debug, Serialize, Deserialize, Request, Response)]
292#[request(get_trade_days)]
293#[response(format = "line")]
294pub struct GetTradeDays {
295    pub date: String,
296    #[serde(skip_serializing_if = "Option::is_none")]
297    pub end_date: Option<String>,
298}
299
300/// 获取所有交易日
301#[derive(Debug, Serialize, Deserialize, Request, Response)]
302#[request(get_all_trade_days)]
303#[response(format = "line")]
304pub struct GetAllTradeDays {}
305
306/// 获取一只股票在一个时间段内的融资融券信息
307/// 参数:
308/// code: 股票代码
309/// date: 开始日期
310/// end_date: 结束日期
311/// 返回:
312/// date: 日期
313/// sec_code: 股票代码
314/// fin_value: 融资余额(元)
315/// fin_buy_value: 融资买入额(元)
316/// fin_refund_value: 融资偿还额(元)
317/// sec_value: 融券余量(股)
318/// sec_sell_value: 融券卖出量(股)
319/// sec_refund_value: 融券偿还量(股)
320/// fin_sec_value: 融资融券余额(元)
321#[derive(Debug, Serialize, Deserialize, Request, Response)]
322#[request(get_mtss)]
323#[response(format = "csv", type = "Mtss")]
324pub struct GetMtss {
325    pub code: String,
326    pub date: String,
327    pub end_date: String,
328}
329
330#[derive(Debug, Serialize, Deserialize)]
331pub struct Mtss {
332    pub date: String,
333    pub sec_code: String,
334    pub fin_value: f64,
335    pub fin_refund_value: f64,
336    pub sec_value: f64,
337    pub sec_sell_value: f64,
338    pub sec_refund_value: f64,
339    pub fin_sec_value: f64,
340}
341
342/// 获取一只股票在一个时间段内的资金流向数据,仅包含股票数据,不可用于获取期货数据
343/// 参数:
344/// code: 股票代码
345/// date: 开始日期
346/// end_date: 结束日期
347/// 返回:
348/// date: 日期
349/// sec_code: 股票代码
350/// change_pct: 涨跌幅(%)
351/// net_amount_main: 主力净额(万): 主力净额 = 超大单净额 + 大单净额
352/// net_pct_main: 主力净占比(%): 主力净占比 = 主力净额 / 成交额
353/// net_amount_xl: 超大单净额(万): 超大单:大于等于50万股或者100万元的成交单
354/// net_pct_xl: 超大单净占比(%): 超大单净占比 = 超大单净额 / 成交额
355/// net_amount_l: 大单净额(万): 大单:大于等于10万股或者20万元且小于50万股或者100万元的成交单
356/// net_pct_l: 大单净占比(%): 大单净占比 = 大单净额 / 成交额
357/// net_amount_m: 中单净额(万): 中单:大于等于2万股或者4万元且小于10万股或者20万元的成交单
358/// net_pct_m: 中单净占比(%): 中单净占比 = 中单净额 / 成交额
359/// net_amount_s: 小单净额(万): 小单:小于2万股或者4万元的成交单
360/// net_pct_s: 小单净占比(%): 小单净占比 = 小单净额 / 成交额
361#[derive(Debug, Serialize, Deserialize, Request, Response)]
362#[request(get_money_flow)]
363#[response(format = "csv", type = "MoneyFlow")]
364pub struct GetMoneyFlow {
365    pub code: String,
366    pub date: String,
367    pub end_date: String,
368}
369
370#[derive(Debug, Serialize, Deserialize)]
371pub struct MoneyFlow {
372    pub date: String,
373    pub sec_code: String,
374    pub change_pct: f64,
375    pub net_amount_main: f64,
376    pub net_pct_main: f64,
377    pub net_amount_xl: f64,
378    pub net_pct_xl: f64,
379    pub net_amount_l: f64,
380    pub net_pct_l: f64,
381    pub net_amount_m: f64,
382    pub net_pct_m: f64,
383    pub net_amount_s: f64,
384    pub net_pct_s: f64,
385}
386
387/// 获取指定日期区间内的龙虎榜数据
388/// 参数:
389/// code: 股票代码
390/// date: 开始日期
391/// end_date: 结束日期
392/// 返回:
393/// code: 股票代码
394/// day: 日期
395/// direction: ALL 表示『汇总』,SELL 表示『卖』,BUY 表示『买』
396/// abnormal_code: 异常波动类型
397/// abnormal_name: 异常波动名称
398/// sales_depart_name: 营业部名称
399/// rank: 0 表示汇总, 1~5 表示买一到买五, 6~10 表示卖一到卖五
400/// buy_value: 买入金额
401/// buy_rate: 买入金额占比(买入金额/市场总成交额)
402/// sell_value: 卖出金额
403/// sell_rate: 卖出金额占比(卖出金额/市场总成交额)
404/// net_value: 净额(买入金额 - 卖出金额)
405/// amount: 市场总成交额
406#[derive(Debug, Serialize, Deserialize, Request, Response)]
407#[request(get_billboard_list)]
408#[response(format = "csv", type = "BillboardStock")]
409pub struct GetBillboardList {
410    pub code: String,
411    pub date: String,
412    pub end_date: String,
413}
414
415#[derive(Debug, Serialize, Deserialize)]
416pub struct BillboardStock {
417    pub code: String,
418    pub day: String,
419    pub direction: String,
420    pub rank: i32,
421    pub abnormal_code: String,
422    pub abnormal_name: String,
423    pub sales_depart_name: String,
424    pub buy_value: f64,
425    pub buy_rate: f64,
426    pub sell_value: f64,
427    pub sell_rate: f64,
428    pub total_value: f64,
429    pub net_value: f64,
430    pub amount: f64,
431}
432
433/// 获取某期货品种在指定日期下的可交易合约标的列表
434/// 参数:
435/// code: 期货合约品种,如 AG (白银)
436/// date: 指定日期
437#[derive(Debug, Serialize, Deserialize, Request, Response)]
438#[request(get_future_contracts)]
439#[response(format = "line")]
440pub struct GetFutureContracts {
441    pub code: String,
442    pub date: String,
443}
444
445/// 获取主力合约对应的标的
446/// 参数:
447/// code: 期货合约品种,如 AG (白银)
448/// date: 指定日期参数,获取历史上该日期的主力期货合约
449#[derive(Debug, Serialize, Deserialize, Request, Response)]
450#[request(get_dominant_future)]
451#[response(format = "line")]
452pub struct GetDominantFuture {
453    pub code: String,
454    pub date: String,
455}
456
457/// 获取单个基金的基本信息
458/// 参数:
459/// code: 基金代码
460/// date: 查询日期, 默认日期是今天。
461/// 返回:
462/// fund_name: 基金全称
463/// fund_type: 基金类型
464/// fund_establishment_day: 基金成立日
465/// fund_manager: 基金管理人及基本信息
466/// fund_management_fee: 基金管理费
467/// fund_custodian_fee: 基金托管费
468/// fund_status: 基金申购赎回状态
469/// fund_size: 基金规模(季度)
470/// fund_share: 基金份额(季度)
471/// fund_asset_allocation_proportion: 基金资产配置比例(季度)
472/// heavy_hold_stocks: 基金重仓股(季度)
473/// heavy_hold_stocks_proportion: 基金重仓股占基金资产净值比例(季度)
474/// heavy_hold_bond: 基金重仓债券(季度)
475/// heavy_hold_bond_proportion: 基金重仓债券占基金资产净值比例(季度)
476#[derive(Debug, Serialize, Deserialize, Request, Response)]
477#[request(get_fund_info)]
478#[response(format = "json", type = "FundInfo")]
479pub struct GetFundInfo {
480    pub code: String,
481    pub date: String,
482}
483
484#[derive(Debug, Serialize, Deserialize)]
485pub struct FundInfo {
486    pub fund_name: String,
487    pub fund_type: String,
488    pub fund_establishment_day: String,
489    pub fund_manager: String,
490    pub fund_management_fee: String,
491    pub fund_custodian_fee: String,
492    pub fund_status: String,
493    pub fund_size: String,
494    pub fund_share: f64,
495    pub fund_asset_allocation_proportion: String,
496    pub heavy_hold_stocks: Vec<String>,
497    pub heavy_hold_stocks_proportion: f64,
498    pub heavy_hold_bond: Vec<String>,
499    pub heavy_hold_bond_proportion: f64,
500}
501
502/// 获取最新的 tick 数据
503/// 参数:
504/// code: 标的代码, 支持股票、指数、基金、期货等。 不可以使用主力合约和指数合约代码。
505/// 返回:
506/// time: 时间
507/// current: 当前价
508/// high: 截至到当前时刻的日内最高价
509/// low: 截至到当前时刻的日内最低价
510/// volume: 累计成交量
511/// money: 累计成交额
512/// position: 持仓量,期货使用
513/// a1_v~a5_v: 五档卖量
514/// a1_p~a5_p: 五档卖价
515/// b1_v~b5_v: 五档买量
516/// b1_p~b5_p: 五档买价
517#[derive(Debug, Serialize, Deserialize, Request, Response)]
518#[request(get_current_tick)]
519#[response(format = "csv", type = "Tick")]
520pub struct GetCurrentTick {
521    pub code: String,
522}
523
524#[derive(Debug, Serialize, Deserialize)]
525pub struct Tick {
526    pub time: f64,
527    pub current: f64,
528    pub high: f64,
529    pub low: f64,
530    pub volumn: f64,
531    pub money: f64,
532    pub position: f64,
533    pub a1_v: f64,
534    pub a2_v: f64,
535    pub a3_v: f64,
536    pub a4_v: f64,
537    pub a5_v: f64,
538    pub a1_p: f64,
539    pub a2_p: f64,
540    pub a3_p: f64,
541    pub a4_p: f64,
542    pub a5_p: f64,
543    pub b1_v: f64,
544    pub b2_v: f64,
545    pub b3_v: f64,
546    pub b4_v: f64,
547    pub b5_v: f64,
548    pub b1_p: f64,
549    pub b2_p: f64,
550    pub b3_p: f64,
551    pub b4_p: f64,
552    pub b5_p: f64,
553}
554
555/// 获取多标的最新的 tick 数据
556/// 参数:
557/// code: 标的代码, 多个标的使用,分隔。每次请求的标的必须是相同类型。标的类型包括: 股票、指数、场内基金、期货、期权
558#[derive(Debug, Serialize, Deserialize, Request, Response)]
559#[request(get_current_ticks)]
560#[response(format = "csv", type = "Tick")]
561pub struct GetCurrentTicks {
562    pub code: String,
563}
564
565/// 获取基金净值/期货结算价等
566/// 参数:
567/// code: 证券代码
568/// date: 开始日期
569/// end_date: 结束日期
570/// 返回:
571/// date: 日期
572/// is_st: 是否是ST,是则返回 1,否则返回 0。股票使用
573/// acc_net_value: 基金累计净值。基金使用
574/// unit_net_value: 基金单位净值。基金使用
575/// futures_sett_price: 期货结算价。期货使用
576/// futures_positions: 期货持仓量。期货使用
577/// adj_net_value: 场外基金的复权净值。场外基金使用
578#[derive(Debug, Serialize, Deserialize, Request, Response)]
579#[request(get_extras)]
580#[response(format = "csv", type = "Extra")]
581pub struct GetExtras {
582    pub code: String,
583    pub date: String,
584    pub end_date: String,
585}
586
587#[derive(Debug, Serialize, Deserialize)]
588pub struct Extra {
589    pub date: String,
590    pub is_st: Option<i8>,
591    pub acc_net_value: Option<f64>,
592    pub unit_net_value: Option<f64>,
593    pub futures_sett_price: Option<f64>,
594    pub futures_positions: Option<f64>,
595    pub adj_net_value: Option<f64>,
596}
597
598/// 获取各种时间周期的bar数据,bar的分割方式与主流股票软件相同, 同时还支持返回当前时刻所在 bar 的数据。get_price 与 get_bars 合并为一个函数
599/// 参数:
600/// code: 证券代码
601/// count: 大于0的整数,表示获取bar的条数,不能超过5000
602/// unit: bar的时间单位, 支持如下周期:1m, 5m, 15m, 30m, 60m, 120m, 1d, 1w, 1M。其中m表示分钟,d表示天,w表示周,M表示月
603/// end_date:查询的截止时间,默认是今天
604/// fq_ref_date:复权基准日期,该参数为空时返回不复权数据
605/// 返回:
606/// date: 日期
607/// open: 开盘价
608/// close: 收盘价
609/// high: 最高价
610/// low: 最低价
611/// volume: 成交量
612/// money: 成交额
613/// 当unit为1d时,包含以下返回值:
614/// paused: 是否停牌,0 正常;1 停牌
615/// high_limit: 涨停价
616/// low_limit: 跌停价
617/// avg: 当天均价
618/// pre_close:前收价
619/// 当code为期货和期权时,包含以下返回值:
620/// open_interest 持仓量
621#[derive(Debug, Serialize, Deserialize, Request, Response)]
622#[request(get_price)]
623#[response(format = "csv", type = "Price")]
624pub struct GetPrice {
625    pub date: String,
626    pub count: u32,
627    pub unit: String,
628    #[serde(skip_serializing_if = "Option::is_none")]
629    pub end_date: Option<String>,
630    #[serde(skip_serializing_if = "Option::is_none")]
631    pub fq_ref_date: Option<String>,
632}
633
634#[derive(Debug, Serialize, Deserialize)]
635pub struct Price {
636    pub date: String,
637    pub open: f64,
638    pub close: f64,
639    pub high: f64,
640    pub low: f64,
641    pub volume: f64,
642    pub money: f64,
643    pub paused: Option<u8>,
644    pub high_limit: Option<f64>,
645    pub low_limit: Option<f64>,
646    pub avg: Option<f64>,
647    pub pre_close: Option<f64>,
648    pub open_interest: Option<f64>,
649}
650
651/// 指定开始时间date和结束时间end_date时间段,获取行情数据
652/// 参数:
653/// code: 证券代码
654/// unit: bar的时间单位, 支持如下周期:1m, 5m, 15m, 30m, 60m, 120m, 1d, 1w, 1M。其中m表示分钟,d表示天,w表示周,M表示月
655/// date: 开始时间,不能为空,格式2018-07-03或2018-07-03 10:40:00,如果是2018-07-03则默认为2018-07-03 00:00:00
656/// end_date:结束时间,不能为空,格式2018-07-03或2018-07-03 10:40:00,如果是2018-07-03则默认为2018-07-03 23:59:00
657/// fq_ref_date:复权基准日期,该参数为空时返回不复权数据
658/// 注:当unit是1w或1M时,第一条数据是开始时间date所在的周或月的行情。当unit为分钟时,第一条数据是开始时间date所在的一个unit切片的行情。
659/// 最大获取1000个交易日数据
660/// 返回:
661/// date: 日期
662/// open: 开盘价
663/// close: 收盘价
664/// high: 最高价
665/// low: 最低价
666/// volume: 成交量
667/// money: 成交额
668/// 当unit为1d时,包含以下返回值:
669/// paused: 是否停牌,0 正常;1 停牌
670/// high_limit: 涨停价
671/// low_limit: 跌停价
672/// 当code为期货和期权时,包含以下返回值:
673/// open_interest 持仓量
674#[derive(Debug, Serialize, Deserialize, Request, Response)]
675#[request(get_price_period)]
676#[response(format = "csv", type = "Price")]
677pub struct GetPricePeriod {
678    pub code: String,
679    pub unit: String,
680    pub date: String,
681    pub end_date: String,
682    #[serde(skip_serializing_if = "Option::is_none")]
683    pub fq_ref_date: Option<String>,
684}
685
686/// 获取tick数据
687/// 股票部分, 支持 2010-01-01 至今的tick数据,提供买五卖五数据
688/// 期货部分, 支持 2010-01-01 至今的tick数据,提供买一卖一数据。 如果要获取主力合约的tick数据,可以先使用get_dominant_future获取主力合约对应的标的
689/// 期权部分,支持 2017-01-01 至今的tick数据,提供买五卖五数据
690/// 参数:
691/// code: 证券代码
692/// count: 取出指定时间区间内前多少条的tick数据,如不填count,则返回end_date一天内的全部tick
693/// end_date: 结束日期,格式2018-07-03或2018-07-03 10:40:00
694/// skip: 默认为true,过滤掉无成交变化的tick数据;
695/// 当skip=false时,返回的tick数据会保留从2019年6月25日以来无成交有盘口变化的tick数据。
696/// 由于期权成交频率低,所以建议请求期权数据时skip设为false
697#[derive(Debug, Serialize, Deserialize, Request, Response)]
698#[request(get_ticks)]
699#[response(format = "csv", type = "Tick")]
700pub struct GetTicks {
701    pub code: String,
702    #[serde(skip_serializing_if = "Option::is_none")]
703    pub count: Option<u32>,
704    pub end_date: String,
705    pub skip: bool,
706}
707
708/// 按时间段获取tick数据
709/// 股票部分, 支持 2010-01-01 至今的tick数据,提供买五卖五数据
710/// 期货部分, 支持 2010-01-01 至今的tick数据,提供买一卖一数据。 如果要获取主力合约的tick数据,可以先使用get_dominant_future获取主力合约对应的标的
711/// 期权部分,支持 2017-01-01 至今的tick数据,提供买五卖五数据
712/// 参数:
713/// code: 证券代码
714/// date: 开始时间,格式2018-07-03或2018-07-03 10:40:00
715/// end_date: 结束时间,格式2018-07-03或2018-07-03 10:40:00
716/// skip: 默认为true,过滤掉无成交变化的tick数据;
717/// 当skip=false时,返回的tick数据会保留从2019年6月25日以来无成交有盘口变化的tick数据。
718/// 注:
719/// 如果时间跨度太大、数据量太多则可能导致请求超时,所有请控制好data-end_date之间的间隔!
720#[derive(Debug, Serialize, Deserialize, Request, Response)]
721#[request(get_ticks_period)]
722#[response(format = "csv", type = "Tick")]
723pub struct GetTicksPeriod {
724    pub code: String,
725    pub date: String,
726    pub end_date: String,
727    pub skip: bool,
728}
729
730/// 获取因子值的 API,点击查看因子列表
731/// 参数:
732/// code: 单只股票代码
733/// columns: 因子名称,因子名称,多个因子用逗号分隔
734/// date: 开始日期
735/// end_date: 结束日期
736/// 返回:
737/// date:日期
738/// 查询因子值
739/// 注:
740/// 为保证数据的连续性,所有数据基于后复权计算
741/// 为了防止单次返回数据时间过长,尽量较少查询的因子数和时间段
742/// 如果第一次请求超时,尝试重试
743#[derive(Debug, Serialize, Deserialize, Request, Response)]
744#[request(get_factor_values)]
745#[response(format = "csv", type = "FactorValue")]
746pub struct GetFactorValues {
747    pub code: String,
748    pub columns: String,
749    pub date: String,
750    pub end_date: String,
751}
752
753#[derive(Debug, Serialize, Deserialize)]
754pub struct FactorValue {
755    pub date: String,
756    pub cfo_to_ev: Option<f64>,
757    pub net_profit_ratio: Option<f64>,
758}
759
760/// 模拟JQDataSDK的run_query方法
761/// run_query api 是模拟了JQDataSDK run_query方法获取财务、宏观、期权等数据
762/// 可查询的数据内容请查看JQData文档
763/// 以查询上市公司分红送股(除权除息)数据为例:
764/// 参数:
765/// table: 要查询的数据库和表名,格式为 database + . + tablename 如finance.STK_XR_XD
766/// columns: 所查字段,为空时则查询所有字段,多个字段中间用,分隔。如id,company_id,columns不能有空格等特殊字符
767/// conditions: 查询条件,可以为空,格式为report_date#>=#2006-12-01&report_date#<=#2006-12-31,条件内部#号分隔,格式: column # 判断符 # value,多个条件使用&号分隔,表示and,conditions不能有空格等特殊字符
768/// count: 查询条数,count为空时默认1条,最多查询1000条
769#[derive(Debug, Serialize, Deserialize, Request, Response)]
770#[request(run_query)]
771#[response(format = "line")]
772pub struct RunQuery {
773    pub table: String,
774    pub columns: String,
775    #[serde(skip_serializing_if = "Option::is_none")]
776    pub conditions: Option<String>,
777    #[serde(skip_serializing_if = "Option::is_none")]
778    pub count: Option<u32>,
779}
780
781/// 获取查询剩余条数
782#[derive(Debug, Serialize, Deserialize, Request, Response)]
783#[request(run_query)]
784#[response(format = "single", type = "i32")]
785pub struct GetQueryCount {}
786
787#[cfg(test)]
788mod tests {
789    use super::*;
790    use serde_json::json;
791
792    #[test]
793    fn test_security_kind_rename() {
794        assert_serde_security_kind("stock", &SecurityKind::Stock);
795        assert_serde_security_kind("fund", &SecurityKind::Fund);
796        assert_serde_security_kind("index", &SecurityKind::Index);
797        assert_serde_security_kind("futures", &SecurityKind::Futures);
798        assert_serde_security_kind("etf", &SecurityKind::ETF);
799        assert_serde_security_kind("lof", &SecurityKind::LOF);
800        assert_serde_security_kind("fja", &SecurityKind::FJA);
801        assert_serde_security_kind("fjb", &SecurityKind::FJB);
802        assert_serde_security_kind("QDII_fund", &SecurityKind::QDIIFund);
803        assert_serde_security_kind("open_fund", &SecurityKind::OpenFund);
804        assert_serde_security_kind("bond_fund", &SecurityKind::BondFund);
805        assert_serde_security_kind("stock_fund", &SecurityKind::StockFund);
806        assert_serde_security_kind("money_market_fund", &SecurityKind::MoneyMarketFund);
807        assert_serde_security_kind("mixture_fund", &SecurityKind::MixtureFund);
808        assert_serde_security_kind("options", &SecurityKind::Options);
809    }
810
811    #[test]
812    fn test_get_all_securities() {
813        let gas = GetAllSecurities {
814            code: SecurityKind::Stock,
815            date: Some(String::from("2020-02-16")),
816        };
817        assert_eq!(
818            serde_json::to_string(&json!({
819                "method": "get_all_securities",
820                "token": "abc",
821                "code": "stock",
822                "date": "2020-02-16",
823            }))
824            .unwrap(),
825            gas.request("abc").unwrap()
826        );
827    }
828
829    fn assert_serde_security_kind(s: &str, k: &SecurityKind) {
830        let str_repr = serde_json::to_string(s).unwrap();
831        assert_eq!(str_repr, serde_json::to_string(k).unwrap());
832        assert_eq!(k, &serde_json::from_str::<SecurityKind>(&str_repr).unwrap());
833    }
834}