【手把手教你】搭建自己的量化分析數(shù)據(jù)庫(kù)

引 言

量化交易的分析基礎(chǔ)是數(shù)據(jù),包括股票歷史交易數(shù)據(jù)弛随、上市公司基本面數(shù)據(jù)、宏觀和行業(yè)數(shù)據(jù)等宁赤。隨著信息流量的日益膨脹舀透,學(xué)會(huì)獲取、查詢(xún)和加工數(shù)據(jù)信息變得越來(lái)越重要决左。對(duì)于鼓搗量化交易的人來(lái)說(shuō)愕够,怎么能說(shuō)不會(huì)玩數(shù)據(jù)庫(kù)呢?目前常用的開(kāi)源(免費(fèi))數(shù)據(jù)庫(kù)有MySQL佛猛、Postgresql 惑芭、Mongodb 和 SQLite (Python自帶),在2018-2019年DB-Engines 排行榜上位居前十(見(jiàn)下圖)继找,可見(jiàn)其使用量和受歡迎程度較高遂跟。這幾個(gè)數(shù)據(jù)庫(kù)各有自己的特點(diǎn)和適用環(huán)境,關(guān)于該學(xué)習(xí)哪一個(gè)或如何學(xué)習(xí)網(wǎng)上有很多相關(guān)資料婴渡。本文主要為大家簡(jiǎn)單介紹如何使用 Python 操作 Postgresql 數(shù)據(jù)庫(kù)(其他數(shù)據(jù)庫(kù)類(lèi)似)幻锁,利用 psycopg2 和 sqlalchemy 實(shí)現(xiàn)?postgresql 與 pandas 的 dataframe 進(jìn)行交互,一步步搭建自己的量化分析數(shù)據(jù)庫(kù)边臼。

PostgreSQL的安裝與使用

安裝 PostgreSQL哄尔。到其官網(wǎng)選擇適合自己電腦配置的版本下載安裝即可(下載地址),安裝過(guò)程除了設(shè)置密碼柠并,其他可選擇全部默認(rèn)岭接,如實(shí)在不會(huì)可參考CSDN上的文章:PostgreSQL安裝詳細(xì)步驟(windows)。安裝完之后在安裝目錄里還可以看到pgAdmin4臼予,這個(gè)是自帶的數(shù)據(jù)庫(kù)圖形化工具鸣戴,最新版是Web 應(yīng)用程序,有點(diǎn)類(lèi)似 Python 的 Jupyter Notebook粘拾,可用來(lái)查看和操作postgresql 數(shù)據(jù)庫(kù)窄锅。

Python上安裝psycopg2 和 sqlalchemy 庫(kù)。psycopg2 是 Python 連接PostgreSQL數(shù)據(jù)庫(kù)的接口半哟,sqlalchemy 應(yīng)用更廣泛酬滤,可連接數(shù)據(jù)庫(kù)(MySQL, SQLite, PostgreSQL)签餐,尤其是對(duì)于 pandas 的dataframe型數(shù)據(jù)寓涨,操作起來(lái)十分方便。關(guān)于這兩個(gè) python 庫(kù)的介紹網(wǎng)上有很多氯檐,這里不詳細(xì)展開(kāi)戒良,在cmd上使用pip install xxx 進(jìn)行安裝即可。

實(shí)例應(yīng)用

首先冠摄,使用 tushare 獲取3000多只股票行情數(shù)據(jù)到本地糯崎,使用psycopg2 和 sqlalchemy 為接口几缭,將數(shù)據(jù)存入本地PostgreSQL數(shù)據(jù)庫(kù)中,方便進(jìn)一步查詢(xún)和操作沃呢。

#先引入后面分析年栓、可視化等可能用到的庫(kù)

importtushareasts

importpandasaspd

importnumpyasnp

importmatplotlib.pyplotasplt

#正常顯示畫(huà)圖時(shí)出現(xiàn)的中文和負(fù)號(hào)

frompylabimportmpl

mpl.rcParams['font.sans-serif']=['SimHei']

mpl.rcParams['axes.unicode_minus']=False

#設(shè)置token

token='輸入你的token'

pro?=?ts.pro_api(token)

數(shù)據(jù)獲取函數(shù),默認(rèn)時(shí)間可以隨時(shí)改動(dòng)

#如果報(bào)錯(cuò)薄霜,把tushare升級(jí)到最新

defget_data(code,start='20190101',end='20190425'):

df=ts.pro_bar(ts_code=code,?adj='qfq',?start_date=start,?end_date=end)

returndf

交易代碼獲取函數(shù)某抓,獲取最新交易日的代碼

#獲取當(dāng)前交易日最新的股票代碼和簡(jiǎn)稱(chēng)

defget_code():

codes?=?pro.stock_basic(list_status='L').ts_code.values

returncodes

插入PostgreSQL 數(shù)據(jù)庫(kù)操作,函數(shù)里使用了try...except...pass是為了避免某些數(shù)據(jù)出錯(cuò)導(dǎo)致程序崩潰惰瓜。

fromsqlalchemyimportcreate_engine

importpsycopg2

engine?=?create_engine('postgresql+psycopg2://postgres:123456@localhost:5432/postgres')

definsert_sql(data,db_name,if_exists='append'):

#使用try...except..continue避免出現(xiàn)錯(cuò)誤否副,運(yùn)行崩潰

try:

data.to_sql(db_name,engine,index=False,if_exists=if_exists)

#print(code+'寫(xiě)入數(shù)據(jù)庫(kù)成功')

except:

pass

由于行情數(shù)據(jù)量龐大,下載比較慢崎坊,先下載20190101至20190425期間日交易數(shù)據(jù)备禀,后續(xù)再不斷更新。

#下載20190101-20190425數(shù)據(jù)并插入數(shù)據(jù)庫(kù)stock_data

#此步驟比較耗費(fèi)時(shí)間奈揍,大致25-35分鐘左右

forcodeinget_code():

data=get_data(code)

insert_sql(data,'stock_data')

#讀取整張表數(shù)據(jù)

df=pd.read_sql('stock_data',engine)

print(len(df))

#輸出結(jié)果:270998

#選取ts_code=000001.SZ的股票數(shù)據(jù)

df=pd.read_sql("select?*?from?stock_data?where?ts_code='000001.SZ'",engine)

print(len(df))

構(gòu)建一個(gè)數(shù)據(jù)更新函數(shù)曲尸,可以下載和插入其他時(shí)間周期的數(shù)據(jù)。2018年1月1日至2019年4月25日打月,數(shù)據(jù)就已達(dá)到108萬(wàn)條队腐。

#更新數(shù)據(jù)或下載其他期間數(shù)據(jù)

defupdate_sql(start,end,db_name):

fromdatetimeimportdatetime,timedelta

forcodeinget_code():

data=get_data(code,start,end)

insert_sql(data,db_name)

print(f'{start}:{end}期間數(shù)據(jù)已成功更新')

#下載20180101-20181231期間數(shù)據(jù)

#只需運(yùn)行一次,不再運(yùn)行后可以注釋掉

#下載數(shù)據(jù)比較慢奏篙,需要20-35分鐘左右

start='20180101'

end='20181231'

db_name='stock_data'

#數(shù)據(jù)下載和存入數(shù)據(jù)庫(kù)

update_sql(start,end,db_name)

#使用pandas的read_sql讀取數(shù)據(jù)

df_all_data=pd.read_sql('stock_data',engine)

print(len(df_all_data))

#輸出結(jié)果:1087050

#查看交易代碼和交易日期個(gè)數(shù)

print(len(df_all_data.ts_code.unique()))

print(len(df_all_data.trade_date.unique()))

#輸出結(jié)果:3604柴淘;319

d=df_all_data.trade_date.unique()

print(d.max())

print(d.min())

2019-04-25T00:00:00.000000000

2018-01-02T00:00:00.000000000

#獲取交易日2019年4月25日數(shù)據(jù)

pd.read_sql("select?*?from?stock_data?where?trade_date='2019-04-25'?",engine).head()

構(gòu)建數(shù)據(jù)查詢(xún)和可視化函數(shù):

defplot_data(condition,title):

frompyechartsimportBar

fromsqlalchemyimportcreate_engine

engine?=?create_engine('postgresql+psycopg2://postgres:123456@localhost:5432/postgres')

data=pd.read_sql("select?*?from?stock_data?where+"+?condition,engine)

count_=data.groupby('trade_date')['ts_code'].count()

attr=count_.index

v1=count_.values

bar=Bar(title,title_text_size=15)

bar.add('',attr,v1,is_splitline_show=False,linewidth=2)

returnbar

查詢(xún)股價(jià)低于2元個(gè)股數(shù)據(jù)分布

c1="close<2"

t1="股價(jià)低于2元個(gè)股時(shí)間分布"

plot_data(c1,t1)

查詢(xún)股價(jià)日漲幅超過(guò)9.5%個(gè)股數(shù)據(jù)分布:

c2="pct_chg>9.5"

t2="股價(jià)漲幅超過(guò)9.5%個(gè)股時(shí)間分布"

plot_data(c2,t2)

查詢(xún)股價(jià)日跌幅超過(guò)-9.5%個(gè)股數(shù)據(jù)分布:

c3="pct_chg<-9.5"

t3="股價(jià)跌幅超過(guò)-9.5%個(gè)股時(shí)間分布"

plot_data(c3,t3)

結(jié)合選股策略對(duì)數(shù)據(jù)庫(kù)進(jìn)行查詢(xún)和提取數(shù)據(jù):

#篩選代碼

#獲取當(dāng)前交易的股票代碼和名稱(chēng)

defget_new_code(date):

#獲取當(dāng)前所有交易股票代碼

df0?=?pro.stock_basic(exchange='',?list_status='L')

df1?=pro.daily_basic(trade_date=date)

df=pd.merge(df0,df1,on='ts_code')

#剔除2017年以后上市的新股次新股

df=df[df['list_date'].apply(int).values<20170101]

#剔除st股

df=df[-df['name'].apply(lambdax:x.startswith('*ST'))]

#剔除動(dòng)態(tài)市盈率為負(fù)的

df=df[df.pe_ttm>0]

#剔除大市值股票

df=df[df.circ_mv<10**5]

#剔除價(jià)格高于20元股票

#df=df[df.close<20]

codes=df.ts_code.values

returncodes

len(get_new_code('20190425'))

#輸出結(jié)果:46

importtalibasta

#20日均線交易策略

deffind_stock(date):

f_code=[]

forcodeinget_new_code(date):

try:

data=df_all_data.loc[df_all_data.ts_code==code].copy()

data.index=pd.to_datetime(data.trade_date)

data=data.sort_index()

data['ma_20']=ta.MA(data.close,timeperiod=20)

ifdata.iloc[-1]['close']>data.iloc[-1]['ma_20']:

f_code.append(code)

except:

pass

returnf_code

fs=find_stock('20190305')

print(f'篩選出的股票個(gè)數(shù):{len(fs)}')

iffs:

df_find_stocks=pd.DataFrame(fs,columns=['ts_code'])

#將選出的股票存入數(shù)據(jù)庫(kù),如果表已存在秘通,替換掉为严,相當(dāng)于每次更新

insert_sql(df_find_stocks,'find_stocks',if_exists='replace')

print('篩選的股票已入庫(kù)')

篩選出的股票個(gè)數(shù):9

篩選的股票已入庫(kù)

#查看數(shù)據(jù)庫(kù)中篩選的股票池

codes=pd.read_sql('find_stocks',engine)

codes=codes.values.tolist()

codes=[c[0]forcincodes]

#print(codes)

對(duì)篩選的股票作進(jìn)一步分析:

select_data=pd.DataFrame()

forcodeincodes:

try:

df_=?df_all_data[df_all_data.ts_code.values==code]

df_.index=pd.to_datetime(df_.trade_date)

df_=df_.sort_index()

select_data[code]=df_.close

except:

pass

select_data.fillna(method='ffill',inplace=True)

select_data.tail()

ret=select_data.apply(lambdax:x/x.shift(1)-1)

ret=ret.dropna()

ret.tail()

prod_ret=ret.apply(lambdax:(1+x).cumprod())

prod_ret.plot(figsize=(12,5))

plt.xlabel('',fontsize=15)

plt.title('股票池累計(jì)凈值',size=15)

ax?=?plt.gca()

ax.spines['right'].set_color('none')

ax.spines['top'].set_color('none')

plt.show()

#根據(jù)代碼從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)

defget_data_from_sql(code):

fromsqlalchemyimportcreate_engine

engine?=?create_engine('postgresql+psycopg2://postgres:123456@localhost:5432/postgres')

data=pd.read_sql(f"select?*?from?stock_data?where?ts_code='{code}'",engine)

data.index=pd.to_datetime(data.trade_date)

data=data.sort_index()

#計(jì)算20日均線

data['ma20']=data.close.rolling(20).mean()

returndata

利用20日均線交易策略,搭建數(shù)據(jù)查詢(xún)和可視化函數(shù)kline_plot()肺稀,完整代碼將分享在知識(shí)星球上第股。對(duì)選出的股票日K線、20日均線话原、成交量夕吻、買(mǎi)入(buy)和賣(mài)出(sell)信號(hào)進(jìn)行可視化。

kline_plot('002790.SZ')

kline_plot('300573.SZ')

結(jié) 語(yǔ)

數(shù)據(jù)庫(kù)操作其實(shí)要學(xué)的東西還很多繁仁,本文旨在拋磚引玉涉馅,簡(jiǎn)單介紹使用Python對(duì)PostgreSQL數(shù)據(jù)庫(kù)與dataframe型數(shù)據(jù)進(jìn)行交互,一步步搭建自己的量化分析數(shù)據(jù)庫(kù)黄虱。由于文中用到的數(shù)據(jù)僅為百萬(wàn)條左右稚矿,實(shí)際上使用excel的csv來(lái)讀寫(xiě)也很快,并且比較直觀,但隨著數(shù)據(jù)的不斷增多晤揣,要建立自己完善的量化分析系統(tǒng)桥爽,數(shù)據(jù)庫(kù)的學(xué)習(xí)就顯得尤為重要了。注意昧识,文中所提及選股方式和股票代碼僅作為示例應(yīng)用钠四,不構(gòu)成任何投資建議。

關(guān)于Python金融量化

專(zhuān)注于分享Python在金融量化領(lǐng)域的應(yīng)用跪楞。加入知識(shí)星球形导,可以免費(fèi)獲取30多g的量化投資視頻資料、公眾號(hào)文章Python完整源碼习霹、量化投資前沿分析框架朵耕,與博主直接交流、結(jié)識(shí)圈內(nèi)朋友等淋叶。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阎曹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子煞檩,更是在濱河造成了極大的恐慌处嫌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斟湃,死亡現(xiàn)場(chǎng)離奇詭異熏迹,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)凝赛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)注暗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人墓猎,你說(shuō)我怎么就攤上這事捆昏。” “怎么了毙沾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵骗卜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我左胞,道長(zhǎng)寇仓,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任烤宙,我火速辦了婚禮遍烦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘门烂。我一直安慰自己乳愉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布屯远。 她就那樣靜靜地躺著蔓姚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪慨丐。 梳的紋絲不亂的頭發(fā)上坡脐,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音房揭,去河邊找鬼备闲。 笑死,一個(gè)胖子當(dāng)著我的面吹牛捅暴,可吹牛的內(nèi)容都是我干的恬砂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蓬痒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼泻骤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起梧奢,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤狱掂,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后亲轨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體趋惨,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年惦蚊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了器虾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蹦锋,死狀恐怖曾撤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晕粪,我是刑警寧澤挤悉,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站巫湘,受9級(jí)特大地震影響装悲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜尚氛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一诀诊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧阅嘶,春花似錦属瓣、人聲如沸载迄。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)护昧。三九已至,卻和暖如春粗截,著一層夾襖步出監(jiān)牢的瞬間惋耙,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工熊昌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绽榛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓婿屹,卻偏偏與公主長(zhǎng)得像灭美,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子昂利,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容