雁起平沙的网络日志

数量金融与R

用R获取大连商品交易所历史数据

| Comments

本文主要讨论如何用R语言从大连商品交易所网站上获取期货合约交易数据

大商所的网站上有提供查询历史的页面。但是它只能对某一个品种查询某一天的报价,或者某一天所有品种的报价,如果我想批量获取交易数据,应该怎么做呢?

首先剖析一下这个页面,用firefox的firebug查看日行情表的代码

日行情表

可以看到,这个表实际上是用iframe实现的,查看页面的源文件可以查出这个iframe引用页面地址为http://www.dce.com.cn/PublicWeb/MainServlet?action=Data_service。用上面的方法继续剖析这个页面,发现它引用了http://www.dce.com.cn/PublicWeb/MainServlet?action=Pu00011_search

先忽略无关的代码,只关注下面这部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<form target="_blank" name="form1" action="/PublicWeb/MainServlet" method="post" onSubmit="return formcheck(this);">
  <input type="hidden" name="action" value="Pu00011_result">
<tr valign="top">
<td height="10"></td>
</tr>
  <tr valign="top">
    <td height="133">
	<div class="title">日 行 情 表</div>
<table border="0" align="center" cellpadding="3" cellspacing="1" width="97%">
  <tr>
    <td class="nametd"> 查询日期:</td>
    <td class="tdjian" ><input name="Pu00011_Input.trade_date" type="text" size="8" maxlength="8">
      <img  align="absmiddle" src="/PublicWeb/include/images/calendar/show.gif" id="Pu00011_Input.trade_date.img" onClick='swapCalendar(document.all("Pu00011_Input.trade_date"))' valign="bottom">
    </td>
    <td class="nametd"> 品  种:</td>
    <td class="tdjian"><select name="Pu00011_Input.variety">
      <option selected value="all">全部</option>
      <option value="a">豆一</option>
      <option value="b">豆二</option>
      <option value="c">玉米</option>
      <option value="j">焦炭</option>
      <option value="l">聚乙烯</option>
      <option value="m">豆粕</option>
      <option value="p">棕榈油</option>
      <option value="v">聚氯乙烯</option>
      <option value="y">豆油</option>
      <option value="s">大豆</option>
    </select></td>
  </tr>
  <tr>
    <td class="nametd"> <p> 行情类型:</p>      </td>
    <td class="tdjian" colspan="3"> <input name="Pu00011_Input.trade_type" type="radio" value="0" checked>期货行情
    <!--hide option
      <input name="Pu00011_Input.trade_type" type="radio" value="1">期权行情
     -->
    </td>
  </tr>
</table>
<script language="javascript">
 calendarImages = ["/PublicWeb/include/images/calendar/prev_year.gif", "/PublicWeb/include/images/calendar/prev_month.gif", "/PublicWeb/include/images/calendar/next_month.gif", "/PublicWeb/include/images/calendar/next_year.gif", "/PublicWeb/include/images/calendar/show.gif", "/PublicWeb/include/images/calendar/hide.gif"]
  getCalendar(document.all("Pu00011_Input.trade_date"), '20130208');
</script>
<table border="0" align="center" cellpadding="5" cellspacing="0">
  <tr>
    <td><input name="Submit" type="submit" class="button" value="查 询" onClick="document.form1.action.value='Pu00011_result';document.form1.target='_blank';">&nbsp;&nbsp;<input name="Submit2" type="submit" class="downbutton" value="下载文本格式" onClick="document.form1.action.value='Pu00012_download';document.form1.target='_self';">&nbsp;&nbsp;<input name="Submit2" type="submit" class="button" value="打 印" onClick="document.form1.action.value='Pu00011_result';document.form1.target='_blank';"></td>
  </tr>
</table>
<table border="0" align="center" cellpadding="1" cellspacing="0" width="97%">
  <tr align="left">
    <td width=20 valign=top>注:</td>
    <td>
     日行情信息 在每日“结算后”发布。历史数据始自2000-05-08。
    </td>
  </tr>
</table>

  </form>

要看懂上面的代码需要点网络编程的知识,请参考w3shool上关于form标签select标签input标签以及onClick事件的介绍。

简单地说上面代码做了以下几件事:

  • 整段代码定义了个表单,名为form1,用于向服务器传输数据,后面用input标签和select标签来定义传递的数据
  • 用了一个input标签和onClick事件onClick='swapCalendar(document.all("Pu00011_Input.trade_date"))'来设置要查询的日期Pu00011_Input.trade_date
  • 用了一个select标签来选择查询的品种Pu00011_Input.variety
  • 用了一个input标签来设置行情类型Pu00011_Input.trade_type,从代码里看,Pu00011_Input.trade_type的值始终是0,代表期货行情;从下面注释掉的部分代码可以看出当Pu00011_Input.trade_type取0时,代表的是期权行情,估计网站还没实现这个功能
  • 然后有一排三个button属性的input标签,所以它们是按钮形式的,并且都有onClick属性,当按下按钮时,会触发javascript脚本,脚本会设置action的值,比如“下载文本格式”这个按钮,按下它会把action的值设置成Pu00012_download

form向服务器传递数据,其实可以等价于用url地址传递参数。比如日期选择了2012年12月6日,品种选择了“豆一”,点击“下载文本格式”,那么对应的地址为http://www.dce.com.cn/PublicWeb/MainServlet?Pu00011_Input.trade_date=20121206&Pu00011_Input.trade_type=0&Pu00011_Input.variety=a&action=Pu00012_download

把地址复制到地址栏,就可以下载文本格式数据了。

那么用R来读取数据的原理就是生成所需数据的url地址,然后用R读取,再经过整理,返回最终数据框。

(dce.r) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 从大连商品交易所网站抓取价格数据 数据源
# http://www.dce.com.cn/PublicWeb/MainServlet?action=Pu00011_search
# Pu00011_Input.trade_date : 查询的日期 
# Pu00011_Input.trade_type : 行情类别   0为期货,1为期权(未开通) 
# Pu00011_Input.variety :期货品种代码,各代码表示的期货品种: 
#  all : 全部 a : 豆一 b : 豆二 c : 玉米 j :焦炭 l: 聚乙烯 
#  m : 豆粕 p : 棕榈油 v : 聚氯乙烯 y : 豆油 s : 大豆


getDceData <- function(dates, contracts, keep.dataFile = T) {
  dceDatabase <- data.frame()
  for (date in dates) {
    for (type in contracts) {

      str1 <- "http://www.dce.com.cn/PublicWeb/MainServlet?Pu00011_Input.trade_date="
      str2 <- "&Pu00011_Input.trade_type=0&Pu00011_Input.variety="
      str3 <- "&action=Pu00012_download"

      url <- paste(str1, date, str2, type, str3, sep = "")
      fileName <- paste("dce.", type, date, ".txt", sep = "")
      lines <- readLines(url)
      # 如果使用的是linux系统,就转换lines的编码
      if (sessionInfo()$R.version$os == "linux-gnu") {
        lines <- iconv(lines, from = "gb2312", to = "UTF-8")
      }
      # 当输入的日期不是交易日或数据文件里合约数据为空时跳过本次循环
      if (any(lines == "<html>") | length(lines) == 5) {
        next
      } else {
        content <- lines[4:(length(lines) - 2)]
        writeLines(content, fileName)
        data <- read.table(fileName, header = T, na.strings = "-")
        if (!keep.dataFile) {
          file.remove(fileName)
        }
        data$date <- date
        dceDatabase <- rbind(dceDatabase, data)
      }
    }
  }
  return(dceDatabase)
}

调用举例:

1
2
3
source("dce.r")
d1 <- getDceData("20121206","a")
d2 <- getDceData(c("20121204","20121205","20121206"), c("a","b"), keep.dataFile = F)

Comments