class: center, middle, inverse, title-slide # 财经数据分析之pedquant包 ### 谢士晨 ### 2019-05-25 --- class: inverse, center, middle # 1/4 简介 --- ## 如何开始 .pull-left[ 首先从 [CRAN](https://cran.r-project.org/web/packages/pedquant/index.html) 安装 **pedquant** (**P**ublic **E**conomic **D**ata and **Quant**itative Analysis) 包: ```r install.packages('pedquant') ``` 或者从 [GitHub](https://github.com/ShichenXie/pedquant) 安装最新版: ```r devtools::install_github('shichenxie/pedquant') ``` **pedquant** 包的帮助文档参见 http://pedquant.com , 或查看R中相应的文档: ```r help(package = 'pedquant') ``` ] .pull-right[ **pedquant** 包提供的函数主要分为三大类: 1. **ed_** (**e**conomic **d**ata 的缩写) 开头的函数,获取来自 [美联储经济数据 FRED](https://research.stlouisfed.org/)、 [中国人民银行 PBC](http://www.pbc.gov.cn/) (进行中)、 [国家统计局 NBS](http://data.stats.gov.cn/) 等机构的经济社会统计数据; 2. **md_** (**m**arket **d**ata 的缩写)开头的函数,获取来自 [雅虎财经 yahoo](https://finance.yahoo.com/) 的全球股票价格数据、 [网易财经 163](http://quotes.money.163.com/) 的上证与深证股票价格与财报数据、 [新浪财经 sina](https://finance.sina.com.cn/futuremarket/) 的国内期货价格数据等; 3. **pq_** (**p**ed**q**uant 的缩写)开头的函数,主要提供了一些数据预处理与可视化等相关功能。 ] --- ## 相关R包 .pull-left[ - 常用的量化分析 R 包见下表<sup>*</sup>:  ] .pull-right[ - 左侧列出的 R 包大部分基于 xts (可扩展时间序列) 数据结构。 - 但以 data.frame (数据框) 为基础的数据处理工具包,例如 [tidyverse](http://tidyverse.org)、 [data.table](http://r-datatable.com),更为大家所熟悉。[tidyquant](https://github.com/business-science/tidyquant) 将量化分析常用功能与 [tidyverse](http://tidyverse.org) 很好的结合起来。 - [pedquant](https://github.com/shichenxie/pedquant) 提供了类似于 [quantmod](https://github.com/joshuaulrich/quantmod) 的功能,但是基于 [data.table](http://r-datatable.com) 包开发,而且提供了我国所特有的财经数据。 ] .footnote[[*] 参考 [Guy Yollin. Introduction to Trading Systems](http://www.r-programming.org/papers)。] --- class: inverse, center, middle # 2/4 获取数据 --- ## 经济社会统计数据 - `ed_nbs` 函数可查询国家统计局 NBS 数据(以 `ed_` 开头的函数可以不用输入参数,而通过交互的方式设定)。 - 其中,`symbol` 与 `subregion` 两个参数可分别通过 `ed_nbs_symbol` 与 `ed_nbs_subregion` 函数获得。 ```r library(data.table) library(pedquant) ``` ``` ## Registered S3 method overwritten by 'xts': ## method from ## as.zoo.xts zoo ``` ```r packageVersion('pedquant') ``` ``` ## [1] '0.1.2.1' ``` ```r # cpi of China dt_nbs = ed_nbs(symbol = c('A01010101','A01010201'), freq = 'monthly', geo_type = 'nation', date_range = 'max', na_rm = TRUE) # data sturcture str(dt_nbs) ``` ``` ## List of 2 ## $ A01010101:Classes 'data.table' and 'data.frame': 47 obs. of 6 variables: ## ..$ symbol: chr [1:47] "A01010101" "A01010101" "A01010101" "A01010101" ... ## ..$ name : chr [1:47] "居民消费价格指数(上年同月=100)" "居民消费价格指数(上年同月=100)" "居民消费价格指数(上年同月=100)" "居民消费价格指数(上年同月=100)" ... ## ..$ date : Date[1:47], format: "2016-01-01" "2016-02-01" "2016-03-01" "2016-04-01" ... ## ..$ value : num [1:47] 102 102 102 102 102 ... ## ..$ geo : chr [1:47] "china" "china" "china" "china" ... ## ..$ unit : chr [1:47] "" "" "" "" ... ## ..- attr(*, ".internal.selfref")=<externalptr> ## $ A01010201:Classes 'data.table' and 'data.frame': 348 obs. of 6 variables: ## ..$ symbol: chr [1:348] "A01010201" "A01010201" "A01010201" "A01010201" ... ## ..$ name : chr [1:348] "居民消费价格指数(上年同月=100)" "居民消费价格指数(上年同月=100)" "居民消费价格指数(上年同月=100)" "居民消费价格指数(上年同月=100)" ... ## ..$ date : Date[1:348], format: "1987-01-01" "1987-02-01" "1987-03-01" "1987-04-01" ... ## ..$ value : num [1:348] 105 105 106 107 108 ... ## ..$ geo : chr [1:348] "china" "china" "china" "china" ... ## ..$ unit : chr [1:348] "" "" "" "" ... ## ..- attr(*, ".internal.selfref")=<externalptr> ``` --- class: clear - `ed_fred` 函数可获取美联储经济数据 FRED。目前该数据库覆盖了87个数据源,拥有53万个美国或国际的数据指标。 - 其中,`symbol` 参数可以通过 `ed_fred_symbol` 函数获取,或者到 FRED 网站上查询。 ```r # cpi of US dt_fred = ed_fred(symbol = 'FLEXCPIM159SFRBATL', date_range = 'max', print_step=0) # data sturcture str(dt_fred) ``` ``` ## List of 1 ## $ FLEXCPIM159SFRBATL:Classes 'data.table' and 'data.frame': 624 obs. of 6 variables: ## ..$ symbol: chr [1:624] "FLEXCPIM159SFRBATL" "FLEXCPIM159SFRBATL" "FLEXCPIM159SFRBATL" "FLEXCPIM159SFRBATL" ... ## ..$ name : chr [1:624] "Flexible Price Consumer Price Index" "Flexible Price Consumer Price Index" "Flexible Price Consumer Price Index" "Flexible Price Consumer Price Index" ... ## ..$ date : Date[1:624], format: "1967-12-01" "1968-01-01" "1968-02-01" "1968-03-01" ... ## ..$ value : num [1:624] 2.81 3.14 3.31 3.62 3.89 ... ## ..$ geo : chr [1:624] "usa" "usa" "usa" "usa" ... ## ..$ unit : chr [1:624] "Percent Change from Year Ago" "Percent Change from Year Ago" "Percent Change from Year Ago" "Percent Change from Year Ago" ... ## ..- attr(*, ".internal.selfref")=<externalptr> ## ..- attr(*, "sorted")= chr "date" ``` --- ## 市场数据 - `md_stock` 函数能够通过雅虎财经查询 [全球上市公司](https://help.yahoo.com/kb/finance-for-web/SLN2310.html?impressions=true) 的股价历史数据,或通过网易财经查询A股上市公司的股价历史数据。 - 雅虎财经提供的历史数据剔除了拆分的影响。网易财经提供的是原始数据,本项目默认对拆分进行了复权。如果需要对分红进一步复权,需要设置adj为TRUE。(复权方法主要参考了 [wind复权算法说明](http://180.96.8.19/windnet/Bulletin/express/fqsf.pdf)) .pull-left[ ```r dt_yahoo = md_stock('000001', date_range = 'max', print_step=0) str(dt_yahoo[[1]][.N]) ``` ``` ## Classes 'data.table' and 'data.frame': 1 obs. of 10 variables: ## $ symbol : chr "000001.SZ" ## $ name : chr "Ping An Bank Co., Ltd." ## $ date : Date, format: "2019-12-27" ## $ open : num 16.5 ## $ high : num 16.9 ## $ low : num 16.4 ## $ close : num 16.6 ## $ close_adj: num 16.6 ## $ volume : num 1.03e+08 ## $ unit : chr "CNY" ## - attr(*, ".internal.selfref")=<externalptr> ## - attr(*, "sorted")= chr "date" ``` ] .pull-right[ ```r dt_163 = md_stock('000001', source = '163', date_range = 'max', print_step=0) str(dt_163[[1]][.N]) ``` ``` ## Classes 'data.table' and 'data.frame': 1 obs. of 14 variables: ## $ symbol : chr "000001.SZ" ## $ name : chr "平安银行" ## $ date : Date, format: "2019-12-27" ## $ open : num 16.5 ## $ high : num 16.9 ## $ low : num 16.4 ## $ close : num 16.6 ## $ change_pct: num 0.972 ## $ volume : num 1.04e+08 ## $ amount : num 1.74e+09 ## $ turnover : num 0.537 ## $ cap_market: num 3.23e+11 ## $ cap_total : num 3.23e+11 ## $ unit : chr "CNY" ## - attr(*, ".internal.selfref")=<externalptr> ## - attr(*, "sorted")= chr "date" ``` ] --- class: clear .pull-left[ - 获取A股上市公司财报,包括 - 财务报表:摘要/利润表/资产负债表/现金流量表 - 与财务指标:主要财务指标/盈利能力/偿还能力/成长能力/营运能力 ```r dt_fs = md_stock_financials( '000001', type='f', print_step=0) t(dt_fs[[1]][1:2]) ``` ``` ## [,1] [,2] ## fs_type "fs0_summary" "fs0_summary" ## fs_name "财务报表摘要" "财务报表摘要" ## var_id "1" "2" ## var_name "营业收入(万元)" "营业成本(万元)" ## date "2004-12-31" "2004-12-31" ## value "531012" "286987" ``` - 1.杜邦分析 - 资产收益率ROE = 总资产收益率ROA * 1/(1-资产负债率asset_liability) - 其中,总资产收益率ROA = 销售净利率profit_margin * 总资产周转率asset_turnover ] .pull-right[ - 2.主要财务指标 <style> table th:nth-of-type(1) { width: 28%; } table th:nth-of-type(2) { width: 22%; } table th:nth-of-type(3) { width: 28%; } table th:nth-of-type(4) { width: 22%; } </style> 指标 | 英文缩写 | 指标 | 英文缩写 :------ | :---- | :------ | :---- 每股收益(元) | EPS | 净利润同比(%) | NPYOY 营业收入(万元) | revenue | 净利润环比(%) | NPQOQ 营业收入同比(%) | revenueYOY | 每股净资产(元) | BVPS 营业收入环比(%) | revenueQOQ | 净资产收益率(%) | ROE_w 净利润(万元) | NP | 每股经营现金流量(元) | CFPS ```r dt_smy = md_stock_financials( '000001', type='summary') ``` ] --- class: clear - 在历史股价中添加常用的估值指标 - 市净率PB = 每股价格/每股净资产BVPS - 市盈率PE = 每股价格/每股收益EPS - 市销率PS = 每股价格/每股销售收入SPS - 市现率PCF = 每股价格/每股现金流CFPS ```r dt_val = md_stock('000001', date_range='max', source='163', valuation=TRUE, print_step=0) tail(dt_val[[1]], 3) ``` ``` ## symbol name date open high low close change_pct volume amount turnover cap_market cap_total pb ## 1: 000001.SZ 平安银行 2019-12-25 16.45 16.56 16.24 16.30 -0.6098 41491798 6.797e+08 0.2138 3.163e+11 3.163e+11 1.098 ## 2: 000001.SZ 平安银行 2019-12-26 16.34 16.48 16.32 16.47 1.0429 37203386 6.104e+08 0.1917 3.196e+11 3.196e+11 1.109 ## 3: 000001.SZ 平安银行 2019-12-27 16.53 16.93 16.43 16.63 0.9715 104257472 1.741e+09 0.5373 3.227e+11 3.227e+11 1.120 ## pe_last pe_trailing pe_forward ps pcf unit ## 1: 12.75 11.30 10.04 2.378 -103.9 CNY ## 2: 12.88 11.42 10.15 2.403 -105.0 CNY ## 3: 13.00 11.53 10.25 2.426 -106.0 CNY ``` --- class: inverse, center, middle # 3/4 数据预处理与可视化 --- ## 技术分析指标 .pull-left[ - `pq_addti` 函数对TTR包的函数进行了适当封装,便于创建技术分析指标。 ```r dt_ti = pq_addti(dt_163, sma = list(n=20), sma = list(n=50), macd = list(), col_kp = FALSE) tail(dt_ti[[1]],2) ``` ``` ## sma_20 sma_50 macd_macd macd_signal ## 1: 15.91 16.2 0.8849 0.3926 ## 2: 15.98 16.2 1.0114 0.5164 ``` ] .pull-right[ - 指标类别: - 根据指标功能可分为移动平均/趋势检测或强度指标/震荡指标/波动率指标/成交量指标/其它 - 根据指标的值大小分为overlays/indicators。 - TTR函数参数: - 价格/成交量/权重: - 不可修改参数,包括OHLC, HLC, HL and volume; - 可修改参数,包括price, prices, x。 均默认设为close或value; - 需要单独设置参数,包括y, w; - 数值参数:例如n, sd, v, nFast, nSlow, nSig, accel,均有默认值,但可以根据需要修改。 ] --- ## 可视化 .pull-left[ ```r # line chart p1 = pq_plot(rbindlist(dt_nbs)[, symbol := symbol[.N]], from = '2000-1-1', chart_type = 'step') print(p1$A01010201) ``` <!-- --> ] .pull-right[ ```r # candlestick chart p2 = pq_plot(dt_val, date_range = 'ytd', chart_type = 'candle') ``` <!-- --> ] --- class: clear .pull-left[ ```r # addti p3 = pq_plot(dt_val, date_range = 'ytd', chart_type = 'bar', addti = list( sma = list(n=20), sma = list(n=50), pb=list())) ``` <!-- --> ] .pull-right[ ```r # linear_trend p4 = pq_plot(dt_val, date_range = 'max', chart_type = 'line', linear_trend = c(-0.8, 0, 0.8)) ``` <!-- --> ] --- class:clear ```r # multiple series dat = md_stock(c('^000001', '^399001'), date_range = 'max', source = '163', print_step = 0) p5 = pq_plot(dat, multi_series = list(ncol=2, scales='free_y'), date_range = 'max', linear_trend = c(-0.8, 0, 0.8), yaxis_log = TRUE) print(p5$multi_series) ``` <img src="index_files/figure-html/p5-1.png" style="display: block; margin: auto;" /> --- class: inverse, center, middle # 4/4 策略开发 --- ## 双均线策略 .pull-left[ ```r # load data ssec = md_stock('^000001', source='163', date_range = 'max', print_step = 0) # technical indicators ti = list( sma=list(n=40), sma=list(n=60), runmin = list(n=30)) # long strategy long = list( enter = 'co(sma_40, sma_60)', exit = 'co(sma_60, sma_40)', stop_limit = 'close == runmin_30', price = 'close', position = 100 ) ``` ] .pull-right[ ```r w = pedquant:::pq_backtest(ssec, addti=ti, rule=list(long=long), stp_lmt_pct=0.03) ``` ``` ## [INFO] backtesting ... ``` <!-- --> ``` ## $`000001.SS` ## TableGrob (2 x 1) "arrange": 2 grobs ## z cells name grob ## p0 1 (1-1,1-1) arrange gtable[layout] ## p1 2 (2-2,1-1) arrange gtable[layout] ``` ] --- class: inverse, center, middle 