金融數(shù)據(jù)一直是數(shù)據(jù)分析的重要數(shù)據(jù)來源,要做金融數(shù)據(jù)分析一定要有一個(gè)金融數(shù)據(jù)庫(kù),這篇博文就來教大家如何在自己的PC上建立一個(gè)簡(jiǎn)易金融數(shù)據(jù)庫(kù)。 “工欲善其事,必先利其器”,建立數(shù)據(jù)庫(kù)首先要有一個(gè)數(shù)據(jù)庫(kù)軟件,這里選擇的是行業(yè)翹楚Oracle。幸運(yùn)的是,Oracle學(xué)微軟的那一套,推出了一個(gè)免費(fèi)但功能有限的Oracle Express版本,雖然是功能有限但對(duì)基本的數(shù)據(jù)庫(kù)操作足夠了。這里是Oracle Express的網(wǎng)址:http://www.oracle.com/technetwork/database/database-technologies/express-edition/overview/index.html。為了更容易的操縱數(shù)據(jù)庫(kù)Oracle SQL Developer也是少不了的,網(wǎng)址:http://www.oracle.com/technetwork/developer-tools/sql-developer/overview/index.html,讀者可以根據(jù)網(wǎng)站的介紹下載安裝這兩款軟件,這里不再贅述。 “水有源,樹有根”,沒有數(shù)據(jù)源的數(shù)據(jù)庫(kù)只是一個(gè)空的容器。這里把滬深兩市的股票交易數(shù)據(jù)作為數(shù)據(jù)源,下面介紹如何獲得這些數(shù)據(jù)。 第一步,獲得股票代碼。交易所網(wǎng)站是獲得股票代碼最可靠的來源,這里給出網(wǎng)址,深交所:http://www./main/marketdata/jypz/colist/;上交所:http://www./assortment/stock/list/name/。讀者可以將這些代碼分別復(fù)制保存在兩個(gè)文件內(nèi),這里不再贅述。 第二步,尋找網(wǎng)絡(luò)數(shù)據(jù)源。有些大型網(wǎng)站提供股票數(shù)據(jù)的下載服務(wù),比如163。這里舉一個(gè)例子,在163官網(wǎng)的股票板塊查詢浦發(fā)銀行(600000),可以順藤摸瓜找到浦發(fā)銀行的歷史交易數(shù)據(jù),網(wǎng)址:http://quotes.money.163.com/trade/lsjysj_600000.html?year=2014&season=4,點(diǎn)擊旁邊的“下載數(shù)據(jù)”按鍵就可以下載數(shù)據(jù)了,數(shù)據(jù)以csv表格的形式存儲(chǔ)。 第三步,自動(dòng)化下載數(shù)據(jù),這也是最復(fù)雜的一步。滬深兩市的可交易股票有幾千只,這些股票的數(shù)據(jù)完全由人工點(diǎn)擊網(wǎng)頁(yè)下載是不現(xiàn)實(shí)的,需要實(shí)現(xiàn)自動(dòng)化下載。這里演示如何用R語(yǔ)言實(shí)現(xiàn)數(shù)據(jù)自動(dòng)下載。在第二步點(diǎn)擊“下載數(shù)據(jù)”按鍵下載數(shù)據(jù)的過程中可以得到下載數(shù)據(jù)的網(wǎng)址,這個(gè)網(wǎng)址是實(shí)現(xiàn)自動(dòng)化下載的關(guān)鍵。打開第二步中的網(wǎng)頁(yè)下載數(shù)據(jù),如果使用的是360瀏覽器,在下載工具中可以得到下載鏈接,如下圖,
如果使用的是火狐瀏覽器,可以在下載管理器中找到下載的文件,右鍵“復(fù)制下載鏈接”,如下圖,
獲得了下載鏈接后,下面分析一下鏈接的組成。剛才獲得的鏈接是:http://quotes.money.163.com/service/chddata.html?code=0600000&start=19991110&end=20141231&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE; CHG;PCHG;TURNOVER;VOTURNOVER;VATURNOVER;TCAP;MCAP,關(guān)鍵字一目了然,600000是股票代碼;如果下載一個(gè)深市的股票可以發(fā)現(xiàn),股票代碼前的0表示滬市,1表示深市;19991110表示開始日期(下載時(shí)可以選擇是上市日還是發(fā)行日,不過這里推薦用上市日),20141231表示截止日期;剩下的都是具體的數(shù)據(jù)項(xiàng)目。 新的問題來了,截止日期可以統(tǒng)一確定,上市日期卻不能,必須分別獲取股票的上市日期。來到網(wǎng)頁(yè)http://quotes.money.163.com/trade/lsjysj_600000.html#01b07,這是查詢數(shù)據(jù)前的狀態(tài),右鍵“查看網(wǎng)頁(yè)源代碼”,搜索一下“上市日”,可以發(fā)現(xiàn)“上市日”前面有一段代碼“value="1999-11-10"”,這就是上市日。
根據(jù)網(wǎng)頁(yè)的特征,可以用R語(yǔ)言自動(dòng)化的分析網(wǎng)頁(yè)內(nèi)容,獲得上市日數(shù)據(jù),代碼如下,
#下載股票上市日期
#download the listingdate of one security
library(RCurl)
SH <- readLines("SH.txt")#獲取證券代碼列表
listing.date <- vector(length = length(SH))
url.date1 <- "http://quotes.money.163.com/trade/lsjysj_"
url.date2 <- ".html#01b07"
for (i in 1:length(SH))
{
#解析網(wǎng)頁(yè),得到listingdate
cat(i,'\n')
url.date <- paste(url.date1, SH[i], url.date2, sep="")
xx <- getURL(url.date)
posi <- regexpr("上市日",xx)
listing.date[i] <- substring(xx,posi[1]-13,posi[1]-4)
}
listing.date.tab <- data.frame(code=SH,listingdate=listing.date,stringsAsFactors=FALSE)
#輸出
write.table(listing.date.tab,file="xxx.txt",sep="\t",quote=FALSE,row.name=FALSE)
把下載好的數(shù)據(jù)按照市場(chǎng)分開,分別保存到txt文件即可,這里不再贅述。保存好的數(shù)據(jù)要稍微處理一下,日期的格式調(diào)整為yyyymmdd,write.table會(huì)把數(shù)據(jù)框的“列名”打印出來,列名也是要去掉的。 有了股票代碼和上市日期數(shù)據(jù)就可以自動(dòng)化下載數(shù)據(jù)了,最好深市滬市分開進(jìn)行,存在不同的文件夾下,R代碼如下,
#下載股票數(shù)據(jù)
library(RCurl)
#http://quotes.money.163.com/service/chddata.html?code=0600030&start=20030106&end=20140920&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;TURNOVER;VOTURNOVER;VATURNOVER;TCAP;MCAP
url1 <- "http://quotes.money.163.com/service/chddata.html?code="
market <- "1" # 1:深市,0:滬市
code <- "000003"
url2 <- "&start="
start <- "19900101"
url3 <- "&end="
end <- "20140920"
url4 <- "&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;TURNOVER;VOTURNOVER;VATURNOVER;TCAP;MCAP"
#文件的存放路徑
file.path <- "F:/download/SS/"
#股票代碼+發(fā)行日期,格式:CODE制表符yyyymmdd
security <- readLines("SS.txt")
code <- vector(length = length(security))
listingdate <- vector(length = length(security))
security.tab <- data.frame(code, listingdate, stringsAsFactors=FALSE)
for (i in 1 : length(security))
{
security.tab[i,] = strsplit(security[i],"\t")
}
for (i in 1 : dim(security.tab)[1])
{
code <- security.tab$code[i]
start <- security.tab$listingdate[i]
cat(i,"\t---",code,"\n")
url <- paste(url1,market,code,url2,start,url3,end,url4,sep="")
file <- paste(file.path,code,".csv",sep="")
download.file(url,destfile=file, method="auto",quiet=T)
}
上一段代碼把股票數(shù)據(jù)下載到指定的文件夾,不過數(shù)據(jù)是以個(gè)股為單位獨(dú)立的存儲(chǔ)在csv文件中的,文件名即是股票代碼。成百上千的csv文件不容易導(dǎo)入數(shù)據(jù)庫(kù),需要把這些文件拼接成幾個(gè)大文件。 “百川匯流”,導(dǎo)入數(shù)據(jù)庫(kù)。在正式導(dǎo)入數(shù)據(jù)庫(kù)之前需要把幾千個(gè)csv文件拼接成幾個(gè)大型文件。為了提高逼格(真實(shí)的原因是建立數(shù)據(jù)庫(kù)的時(shí)候本人還不會(huì)Python),這里用C++完成拼接文件的工作,其實(shí)有Python基礎(chǔ)的讀者也可以用Python來完成。文件拼接的C++程序如下,
#include <vector>
#include <fstream>
#include <string>
int main(void)
{
//處理股票數(shù)據(jù)
const int N = 1000;
ifstream fin;
vector<string> file_list,ff;
char x[N];
string ss;
//獲取要處理的文件列表
fin.open("fff.txt");
while (!fin.eof())
{
fin.getline(x, N, '\n');
ss.assign(x);
if (ss.size() > 0)
{
file_list.push_back(ss);
}
}
fin.close();
//cout<<file_list.size()<<endl;
ofstream fout, fout0,fout1,fout2,fout3,fout4,fout5;
string obj_file("x.csv"),path1("F:/download/obj/"),path2("F:/download/outh/");
需要解釋一下,第一步獲取要處理的文件的文件名列表,前半部分為滬市,后半部分為深市,列表存放在fff.txt文件(獲取文件名列表可以用R中的dir函數(shù))。第二步把所有文件轉(zhuǎn)移到同一個(gè)文件夾下,運(yùn)行C++程序處理文件,將文件歸并到6個(gè)文件中。拼接的同時(shí),在數(shù)據(jù)中增加了“市場(chǎng)”字段,SH表示滬市,SS表示深市。數(shù)據(jù)的日期格式因該是yyyymmdd,C++代碼中已經(jīng)通過ss.erase()調(diào)整過了。 文件拼接完成之后,按照數(shù)據(jù)的存儲(chǔ)形式在Oracle中建立相應(yīng)的“表”,在用SQL Developer將拼接好的csv文件中的數(shù)據(jù)導(dǎo)入Oracle就可以了,這完全是數(shù)據(jù)庫(kù)操作,不再贅述。 做完上面幾步就完成了股票數(shù)據(jù)庫(kù)的建立,勝利收官。同理,舉一反三地可以建立股票指數(shù)數(shù)據(jù)庫(kù)。下面講一下注意事項(xiàng): 1.在數(shù)據(jù)下載的時(shí)候可能遇到打不開下載鏈接的情況,這時(shí)候R程序會(huì)報(bào)錯(cuò)并停止,這時(shí)候需要人工的跳過這個(gè)鏈接,重新運(yùn)行程序,直接進(jìn)入下一步的循環(huán),所以下載的時(shí)候人工監(jiān)控是少不了的。 2.建議用最新版的R運(yùn)行程序,之前的版本在下載文件時(shí)存在內(nèi)存溢出的現(xiàn)象,在下載幾百個(gè)文件之后會(huì)因?yàn)閮?nèi)存不足而強(qiáng)行終止運(yùn)行。 3.在數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫(kù)之后建議人工檢驗(yàn)一下每一個(gè)字段,把存在空值的行刪掉。
最后借助RODBC包把Oracle和R連接起來,給出一個(gè)數(shù)據(jù)分析的例子,計(jì)算一下浦發(fā)銀行600000和上證指數(shù)000001之間的線性關(guān)系,R代碼如下,
rm(list=ls())
library(RODBC)
channel <- odbcConnect(dsn="***",uid="***",pwd="***")
sql1 <- "SELECT dates, close, pre_close FROM idx
where
dates in
(
SELECT dates FROM idx where code='000001'
INTERSECT
SELECT dates FROM security where code='600000'
and
close > 0
and
dates >= to_date('20100101', 'yyyymmdd')
)
and
code = '000001'
order by dates asc"
sql2 <- "SELECT dates, close, pre_close FROM security
where
dates in
(
SELECT dates FROM idx where code='000001'
INTERSECT
SELECT dates FROM security where code='600000'
and
close > 0
and
dates >= to_date('20100101', 'yyyymmdd')
)
and
code = '600000'
order by dates asc"
i000001 <- sqlQuery(channel, sql1)
head(i000001)
s600000 <- sqlQuery(channel, sql2)
head(s600000)
t <- s600000$DATES
s <- log(s600000$CLOSE) - log(s600000$PRE_CLOSE)
i <- log(i000001$CLOSE) - log(i000001$PRE_CLOSE)
plot(i, s, pch = 20, xlab="000001", ylab="600000")
capm.lm <- lm(s~i)
abline(coef = capm.lm$coe, co="red", lwd=2)
|
|