RでXBRLデータを取得してみた
※この記事は R Advent Calendar 2014 - Qiita の 15日目の記事です。
諸事情により発表出来なかったネタを書きたいと思い、書いてみました。ポストが長いので、前編/後編の二本立てにしました。後編は、R Advent Calendar 2014 - Qiita の 19日目の記事になります。
また、(R Adventなのに)記述が金融や会計の知識を前提としているところがありますが、ご容赦ください。後で加筆するかもしれません。
前・後編ポストのサマリー
- 以前著者より、以下の献本を頂きました。
- これを読んで、上場企業の有価証券報告書について、こんな感じの財務データの一覧表を作りたい、と思い立って実験した、だけの話です。
- (下記のように)他の例もあるのは知ってはいますが、自分で仕組みを持っていた方が、何かと面白いかも?と変な気が出たまでです。
証券コード | 企業名 | FY | 現預金 | 売掛金 | … | 売上 | … |
---|---|---|---|---|---|---|---|
1301 | 極洋 | 2014 | 3,456 | 24,393 | … | 202,387 | … |
1332 | 日本水産 | 2014 | 6,849 | 73,250 | … | 604,249 | … |
1333 | マルハニチロ | 2014 | 13,952 | 98,198 | … | 851,708 | … |
… | … | … | … | … | … | … | … |
(前編)RでXBRLデータを取得してみた → 本ポスト
(後編)取得データからデータマートを作ってみた → 後日公開
なぜこのような事を思い立ったのか?
気が向いたら、別立てで書くかも知れません。なんとなく面白そうだから、というのもあったりはします。*1
他のサービス
私の知るところですと、以下のものがあります。なお、検索範囲の網羅性については確保されていません。あらかじめご了承ください。
前・後編全体を通した手順
図示するとこんなところです。
プログラム本体
以前著者より献本頂いた本のソースが下敷きになっております。下記リンクより、書籍に掲載されいるサンプルコードのDLも可能です。
金融データ解析の基礎 / 金 明哲 編 高柳 慎一 井口 亮 水木 栄 著 | 共立出版
XML, XBRLとは何ぞや、XBRLの仕様について、ソースの説明、等々は上記本が詳しいので、是非ともお買い求めの上ご参照ください。
注意
- ソースでは、有限会社プレシス様「EDINET-適時開示情報(TDnet)参照API」を利用しております。ご利用は、節度を守った上でお願いします。
- と言いながら約1週間、そこそこヒドイことしました。すみません。
- ソースは、新規上場銘柄や一部変則的な名称の場合に上手く行かないことがあり得ます。(組織再編有価証券報告書、等)
- 下記の使い方そのままでは、設定取得期間後に上場廃止となった銘柄については取得できません。上場廃止銘柄は、東証HPより取得可能なので、(私は未テストですが)廃止銘柄も対応可能なはずです。
但し、過去分一覧はPDFなのですが…。→HTMLになりました。- 実は、下記のソースはXBRLを取得後に改変してます。テストをすれば良いのですが、適切なテストケースを選ぶ時間がなかったとか。
1. 書籍のサンプルコードからの改変点(含むToDo)
2. 使い方
1. プログラムを置いたディレクトリに、"master"という名前のフォルダーを作成します。
2. http://www.jpx.co.jp/markets/statistics-equities/misc/01.html/より、上場企業のコード一覧EXCELを取得し、"[下記の略称名].txt"のタブ区切りで保存します
- 下記略称名は、適宜改変可能です。略称名が出力の名称になります。
- 上記注意のとおり、取得できるのは「設定期間内で、かつ現時点でも上場している銘柄」です
市場名 | 略称 |
---|---|
市場第一部 (内国株) | TSE1 |
市場第二部 | TSE2 |
マザーズ (内国株) | Mothers |
JASDAQ(グロース) | JQG |
JASDAQ(スタンダード) | JQS |
3. 以下ソースを、適宜改変の上実行して下さい。
3. プログラム
INPUT
- プレシス様API
OUTPUT
- "./master/master_SIC.txt" -> 入力した銘柄一覧
- "./data"以下に、DLしたzip済XBRL
- "./downloaded_XBRL.txt" -> DLしたXBRL一覧表。中身はこんな感じ
1301 E00012 ED2013062500588 【E00012】株式会社 極洋 有価証券報告書 ‐ 第90期(平成24年4月1日 ‐ 平成25年3月31日) http://resource.ufocatch.com/data/edinet/ED2013062500588 20130625 1332 E00014 ED2013062601290 【E00014】日本水産株式会社 有価証券報告書 ‐ 第98期(平成24年4月1日 ‐ 平成25年3月31日) http://resource.ufocatch.com/data/edinet/ED2013062601290 20130626 1352 E00017 ED2013062500566 【E00017】株式会社ホウスイ 有価証券報告書 ‐ 第78期(平成24年4月1日 ‐ 平成25年3月31日) http://resource.ufocatch.com/data/edinet/ED2013062500566 20130625 1378 E00007 ED2013062802178 【E00007】株式会社雪国まいたけ 有価証券報告書 ‐ 第30期(平成24年4月1日 ‐ 平成25年3月31日) http://resource.ufocatch.com/data/edinet/ED2013062802178 20130628 1379 E00008 ED2013062703175 【E00008】ホクト株式会社 有価証券報告書 ‐ 第50期(平成24年4月1日 ‐ 平成25年3月31日) http://resource.ufocatch.com/data/edinet/ED2013062703175 20130627 1380 E00344 ED2013062600250 【E00344】株式会社秋川牧園 有価証券報告書 ‐ 第34期(平成24年4月1日 ‐ 平成25年3月31日) http://resource.ufocatch.com/data/edinet/ED2013062600250 20130626
ソースコード "01.getXBRL.R"
rm(list=ls()) invisible(gc()); invisible(gc()) ##### library library("RCurl") library("XML") library("plyr") ##### 証券コード取得 tmp.list <- paste0("./master/", dir("./master/", pattern = "*.txt") ) tmp.master.SIC <- list() master.SIC <- c() for (i in 1:length(tmp.list)) { mkt.name <- sub(".txt", "", unlist(strsplit(tmp.list[i], "/"))[3]) tmp.master.SIC[[i]] <- read.table( tmp.list[i], sep = "\t", header = TRUE, stringsAsFactors = FALSE) tmp.master.SIC[[i]] <- cbind( mkt.name, tmp.master.SIC[[i]] ) master.SIC <- rbind(master.SIC, tmp.master.SIC[[i]][1:6]) } colnames(master.SIC) <- sub("X","",colnames(master.SIC)) rm(list=c("i", "mkt.name", ls(pattern = "tmp*"))) # cleanup # 証券コードリストの出力 write.table(master.SIC, "./master/master_SIC.txt", sep = "\t" , col.names = TRUE, row.names = TRUE) ##### XBRL取得 ### 前準備 # 対象企業の証券コードをクエリワードにする SICs <- as.character(master.SIC$コード) # XBRL形式のファイル一式をダウンロード,"data"フォルダに保存 dir.create("data") # "data"フォルダを作成 # 定数設定 api.service.url <- "http://resource.ufocatch.com/atom/edinetx" # APIのURI # 取得期間を設定 date.from <- as.Date('2013/6/1') date.to <- as.Date('2013/6/30') # XBRL取得の本体 for (strSIC in SICs[1:1]){ # 指定秒数のWAIT Sys.sleep(10) # リクエストを送信する strURL <- paste0(api.service.url, "/query/", strSIC) # URIと証券コードを結合 Sys.sleep(1) # WAITを入れないとエラーとなることがある objQuery <- httpGET(strURL) # レスポンスを取得 # xmlParseにより,APIのResponseをXMLInternalDocument形式に変換 objXML <- xmlParse(objQuery,encoding="UTF-8") # 名前空間の定義をベクトル形式(simplify=TRUE) で取得 objXML.namespaces <- xmlNamespaceDefinitions(objXML,simplify=TRUE) # デフォルトの名前空間に適当な接頭辞を付け直す names(objXML.namespaces)[ names(objXML.namespaces)=="" ] <- "default" # 要素ノード:entryを指定 nodes.entry <- getNodeSet(objXML,"//default:entry",namespaces=objXML.namespaces) # 有価証券報告書のみを抽出 lst.YUHO <- list() for(node in nodes.entry){ # <entry>タグをひとつずつ処理 lst.temp <- list() # 提出書類のタイトルを取得→要素ノード:title の内容を取得 title.value <- xpathSApply(node,path="default:title",fun=xmlValue,namespaces=objXML.namespaces) # 提出書類のタイトルに「有価証券報告書」を含むか否かを判定 is.YUHO <- grepl(pat="*有価証券報告書*",x=title.value) if(is.YUHO){ #「含む」と判定された場合 # 提出日で判定 is.date <- xpathSApply(node,path="default:updated",fun=xmlValue,namespaces=objXML.namespaces) is.date <- as.Date(substr(is.date, 1, 10)) if (date.from <= is.date && is.date <= date.to) { # 提出日が指定範囲内の場合 # IDを取得 lst.temp$id <- xpathSApply(node,path="default:id",fun=xmlValue,namespaces=objXML.namespaces) lst.temp$title <- title.value # <link>タグのうち,type='application/zip'のhref属性を取得 lst.temp$url <- xpathSApply(node,path="default:link[@type='application/zip']/@href",namespaces=objXML.namespaces) lst.YUHO[[lst.temp$id]] <- lst.temp } } } # XBRLデータを保存 # 抽出した情報を保存 # plyr パッケージのldply 関数でデータフレームに変換 dat.export <- ldply(lst.YUHO,.fun=data.frame)[, -1] if(!sum(dim(dat.export))==0){ # 該当なしの場合は抜ける for(lst in lst.YUHO){ temp <- getBinaryURL(url=lst$url ) # バイナリデータ writeBin( temp, paste0("data/",lst$id,".zip") ) # zip形式で保存 } dat.export <- cbind(strSIC , substr(dat.export$title, 2, 7) , dat.export) write.table(dat.export, file = "downloaded_XBRL.txt" , sep = "\t", append = TRUE , row.names = FALSE, col.name = FALSE) } } rm(list = ls()) # cleanup
感想
Disclaimer
本記事は個人的な勉強のために作成したものです。本情報の内容については万全を期しておりますが、その内容を保証するものではありません。これらの情報によって生じたいかなる損害についても、筆者は一切の責任を負いません。
なお、本資料における意見、見解等はすべて筆者の個人的なものであり、筆者の属する組織の意見、見解等ではないことをご了承ください。
*1:書いたら今日中に間に合いそうもなかったので、というのはナイショ。