python量化投資研究

使用Wind開放應用接口,可以輕鬆獲取各種金融數據、快速開發個性化應用、構建量化投資平臺、實現自動化生成報表、監控市場行情,或者將Wind數據服務與自有系統完美集成。

http://www.dajiangzhang.com/document

 

個人做股票研究最難得的是數據源的獲取,除了從各大財經網站爬取數據外,從各大財經數據供應商提供的相關接口爬取或者下載,效率更高,數據質量也更有保證。

Wind終端一直是國內投資領域機構投資者必備的工具,但是對小散來說每年動輒幾萬至幾十萬不等的費用往往令我們望而卻步。好不容易在大獎章網站找到了Wind量化接口個人版 API接口,雖說沒有Wind終端完整的功能,但是從基礎數據質量和接口易學程度講,都要方便很多。

很早之前研究過,一直擱置了,這兩天重新撿起來完善後,效率果然比從財經網站爬取數據效率高很多。 話不多說,分享下這兩天研究的成果。

首先從大獎章網站下載wind量化接口個人版(免費,這點很難得),根據提示安裝、註冊,然後就可以快樂的玩耍了。

API 接口插件(無需安裝Wind終端)及文檔:

http://www.dajiangzhang.com/document

下面上代碼,已在代碼中作了註釋,供需要的朋友參考。

每週get一個小技能,一年後也必是收穫滿滿啊,新年加油!

Python代碼:(後續持續完善,目標是搭建一個本地的量化投資數據庫)

# -*- coding:utf-8 -*-
####################################################################################################################
'''
 程序:Wind股票數據下載
 功能:從Wind終端或者Wind資訊量化接口個人免費版中下載股票相關數據,保存至本地MySQL數據庫,以進一步加工處理和分析
 創建時間:2016/01/15  V1.01 創建版本,Python2.7
 更新歷史:2017/01/06  V1.02 從本地文件讀取股票代碼列表;升級到Python3.5版本
           2017/01/07  V1.03 封裝爲函數,便於調試和代碼管理
           2017/01/08  V1.04 封裝爲類,爲後續完善功能準備。自動從Wind中獲取股票列表,獨立運行;增加日誌和參數處理
 環境和類庫:使用Python 3.5及第三方庫pandas、WindPy、sqlalchemy
             數據庫:MySQL 5.7.16
             Wind資訊量化接口 個人版(免費),可從Wind官網或大獎章網站下載安裝,註冊即可使用
 作者:yuzhucu
'''
####################################################################################################################
import pandas as pd
from WindPy import *
from sqlalchemy import create_engine
import datetime,time
import os
 
class WindStock():
 
    def getCurrentTime(self):
        # 獲取當前時間
        return time.strftime('[%Y-%m-%d %H:%M:%S]', time.localtime(time.time()))
 
    def AStockHisData(self,symbols,start_date,end_date,step=0):
        '''
        逐個股票代碼查詢行情數據
        wsd代碼可以藉助 WindNavigator自動生成copy即可使用;時間參數不設,默認取當前日期,可能是非交易日沒數據;
        只有一個時間參數時,默認作爲爲起始時間,結束時間默認爲當前日期;如設置兩個時間參數則依次爲起止時間
        '''
        print(self.getCurrentTime(),": Download A Stock Starting:")
        for symbol in symbols:
             w.start()
             try:
                 #stock=w.wsd(symbol,'trade_code,open,high,low,close,volume,amt',start_date,end_date)
                 '''
                 wsd代碼可以藉助 WindNavigator自動生成copy即可使用;
                 時間參數不設,默認取當前日期,可能是非交易日沒數據;
                 只有一個時間參數,默認爲起始時間到最新;如設置兩個時間參數則依次爲起止時間
                '''
                 stock=w.wsd(symbol, "trade_code,open,high,low,close,pre_close,volume,amt,dealnum,chg,pct_chg,vwap, adjfactor,close2,turn,free_turn,oi,oi_chg,pre_settle,settle,chg_settlement,pct_chg_settlement, lastradeday_s,last_trade_day,rel_ipo_chg,rel_ipo_pct_chg,susp_reason,close3, pe_ttm,val_pe_deducted_ttm,pe_lyr,pb_lf,ps_ttm,ps_lyr,dividendyield2,ev,mkt_cap_ard,pb_mrq,pcf_ocf_ttm,pcf_ncf_ttm,pcf_ocflyr,pcf_nflyr,trade_status", start_date,end_date)
                 index_data = pd.DataFrame()
                 index_data['trade_date']=stock.Times
                 stock.Data[0]=symbol
                 index_data['stock_code']=stock.Data[0]
                 #index_data['stock_code'] =symbol
                 index_data['open'] =stock.Data[1]
                 index_data['high'] =stock.Data[2]
                 index_data['low']  =stock.Data[3]
                 index_data['close']=stock.Data[4]
                 index_data['pre_close']=stock.Data[5]
                 index_data['volume']=stock.Data[6]
                 index_data['amt']=stock.Data[7]
                 index_data['dealnum']=stock.Data[8]
                 index_data['chg']=stock.Data[9]
                 index_data['pct_chg']=stock.Data[10]
                 #index_data['pct_chg']=index_data['pct_chg']/100
                 index_data['vwap']=stock.Data[11]
                 index_data['adj_factor']=stock.Data[12]
                 index_data['close2']=stock.Data[13]
                 index_data['turn']=stock.Data[14]
                 index_data['free_turn']=stock.Data[15]
                 index_data['oi']=stock.Data[16]
                 index_data['oi_chg']=stock.Data[17]
                 index_data['pre_settle']=stock.Data[18]
                 index_data['settle']=stock.Data[19]
                 index_data['chg_settlement']=stock.Data[20]
                 index_data['pct_chg_settlement']=stock.Data[21]
                 index_data['lastradeday_s']=stock.Data[22]
                 index_data['last_trade_day']=stock.Data[23]
                 index_data['rel_ipo_chg']=stock.Data[24]
                 index_data['rel_ipo_pct_chg']=stock.Data[25]
                 index_data['susp_reason']=stock.Data[26]
                 index_data['close3']=stock.Data[27]
                 index_data['pe_ttm']=stock.Data[28]
                 index_data['val_pe_deducted_ttm']=stock.Data[29]
                 index_data['pe_lyr']=stock.Data[30]
                 index_data['pb_lf']=stock.Data[31]
                 index_data['ps_ttm']=stock.Data[32]
                 index_data['ps_lyr']=stock.Data[33]
                 index_data['dividendyield2']=stock.Data[34]
                 index_data['ev']=stock.Data[35]
                 index_data['mkt_cap_ard']=stock.Data[36]
                 index_data['pb_mrq']=stock.Data[37]
                 index_data['pcf_ocf_ttm']=stock.Data[38]
                 index_data['pcf_ncf_ttm']=stock.Data[39]
                 index_data['pcf_ocflyr']=stock.Data[40]
                 index_data['pcf_ncflyr']=stock.Data[41]
                 index_data['trade_status']=stock.Data[42]
                 index_data['data_source']='Wind'
                 index_data['created_date']=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
                 index_data['updated_date']=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
                 index_data = index_data[index_data['open'] > 0]
                 #index_data.fillna(0)
                 try:
                    index_data.to_sql('stock_daily_data',engine,if_exists='append');
                 except Exception as e:
                     #如果寫入數據庫失敗,寫入日誌表,便於後續分析處理
                     error_log=pd.DataFrame()
                     error_log['trade_date']=stock.Times
                     error_log['stock_code']=stock.Data[0]
                     error_log['start_date']=start_date
                     error_log['end_date']=end_date
                     error_log['status']=None
                     error_log['table']='stock_daily_data'
                     error_log['args']='Symbol: '+symbol+' From '+start_date+' To '+end_date
                     error_log['error_info']=e
                     error_log['created_date']=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
                     error_log.to_sql('stock_error_log',engine,if_exists='append')
                     print ( self.getCurrentTime(),": SQL Exception :%s" % (e) )
                     continue
                 w.start()
             except Exception as e:
                     #如果讀取處理失敗,可能是網絡中斷、頻繁訪問被限、歷史數據缺失等原因。寫入相關信息到日誌表,便於後續補充處理
                     error_log=pd.DataFrame()
                     error_log['trade_date']=stock.Times
                     error_log['stock_code']=stock.Data[0]
                     error_log['start_date']=start_date
                     error_log['end_date']=end_date
                     error_log['status']=None
                     error_log['table']='stock_daily_data'
                     error_log['args']='Symbol: '+symbol+' From '+start_date+' To '+end_date
                     error_log['error_info']=e
                     error_log['created_date']=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
                     error_log.to_sql('stock_error_log',engine,if_exists='append')
                     print ( self.getCurrentTime(),":index_data %s : Exception :%s" % (symbol,e) )
                     time.sleep(sleep_time)
                     w.start()
                     continue
             print(self.getCurrentTime(),": Downloading [",symbol,"] From "+start_date+" to "+end_date)
        print(self.getCurrentTime(),": Download A Stock Has Finished .")
 
    def getAStockCodesFromCsv(self):
        '''
        獲取股票代碼清單,鏈接數據庫
        '''
        file_path=os.path.join(os.getcwd(),'Stock.csv')
        stock_code = pd.read_csv(filepath_or_buffer=file_path, encoding='gbk')
        Code=stock_code.code
        return Code
 
    def getAStockCodesWind(end_date=time.strftime('%Y%m%d',time.localtime(time.time()))):
        '''
        通過wset數據集獲取所有A股股票代碼,深市代碼爲股票代碼+SZ後綴,滬市代碼爲股票代碼+SH後綴。
        如設定日期參數,則獲取參數指定日期所有A股代碼,不指定日期參數則默認爲當前日期
        :return: 指定日期所有A股代碼,不指定日期默認爲最新日期
        '''
        w.start()
        #加日期參數取最指定日期股票代碼
        #stockCodes=w.wset("sectorconstituent","date="+end_date+";sectorid=a001010100000000;field=wind_code")
        #不加日期參數取最新股票代碼
        stockCodes=w.wset("sectorconstituent","sectorid=a001010100000000;field=wind_code")
        return stockCodes.Data[0]
        #return stockCodes
 
def main():
    '''
    主調函數,可以通過參數調整實現分批下載
    '''
    global engine,sleep_time,symbols
    sleep_time=5
    windStock=WindStock()
    engine = create_engine('mysql://root:root@localhost/invest?charset=utf8')
    #start_date='20100101'
    #end_date='20131231'
    #symbols=windStock.getAStockCodesFromCsv()#通過文件獲取股票代碼
    #symbols=windStock.getAStockCodesWind()
    #通過Wind API獲取股票代碼,默認取最新的,可以指定取歷史某一日所有A股代碼
    #symbols=['000001.SZ', '000002.SZ', '000004.SZ']#通過直接賦值獲取股票代碼用於測試
    #print (symbols)
    #windStock.AStockHisData(symbols,start_date,end_date)
    for i in range(2013,1990,-1):
         start_date=str(i)+'0101'
         end_date=str(i)+'1231'
         print (start_date,end_date,'Starting')
         symbols=windStock.getAStockCodesWind()
         windStock.AStockHisData(symbols,start_date,end_date)
         print (start_date,end_date,'Finished')
 
 
 
def test():
    '''
    測試腳本,新增和優化功能時使用
    '''
    symbol='000001.SZ'
    start_date='20170101'
    end_date='20170109'
    #w.start();
    #stock=w.wsd(symbol,'trade_code,open,high,low,close')
    #stock=w.wsd(symbol, "trade_status,open,high,low,close,pre_close,volume,amt,dealnum,chg,pct_chg,vwap, adjfactor,close2,turn,free_turn,oi,oi_chg,pre_settle,settle,chg_settlement,pct_chg_settlement, lastradeday_s,last_trade_day,rel_ipo_chg,rel_ipo_pct_chg,susp_reason,close3, pe_ttm,val_pe_deducted_ttm,pe_lyr,pb_lf,ps_ttm,ps_lyr,dividendyield2,ev,mkt_cap_ard,pb_mrq,pcf_ocf_ttm,pcf_ncf_ttm,pcf_ocflyr,pcf_nflyr", start_date,end_date)
    #stock=w.wsd("000001.SZ", "pre_close,open,high,low,close,volume,amt,dealnum,chg,pct_chg,vwap,adjfactor,close2,turn,free_turn,oi,oi_chg,pre_settle,settle,chg_settlement,pct_chg_settlement,lastradeday_s,last_trade_day,rel_ipo_chg,rel_ipo_pct_chg,trade_status,susp_reason,close3", "2016-12-09", "2017-01-07", "adjDate=0")
    #print (stock)
 
    for i in range(2014,1990,-1):
         start_date=str(i)+'0101'
         end_date=str(i)+'1231'
         print (start_date,end_date)
 
if __name__ == "__main__":
    main()
 


MySQL建表腳本:

use invest ;
drop TABLE IF  EXISTS stock_daily_data ;
CREATE TABLE IF NOT EXISTS stock_daily_data (
  index1 bigint(20) NOT NULL,
  trade_date date NOT NULL COMMENT '交易日期',
  stock_code varchar(100) NOT NULL COMMENT '股票代碼',
  open double DEFAULT NULL COMMENT '開盤價',
  high double DEFAULT NULL COMMENT '最高價',
  low double DEFAULT NULL COMMENT '最低價',
  close double DEFAULT NULL COMMENT ' 收盤價,證券在交易日所在指定週期的最後一條行情數據中的收盤價',
  volume double DEFAULT NULL COMMENT '成交量',
  amt double DEFAULT NULL COMMENT '成交金額',
  pct_chg double DEFAULT NULL COMMENT '漲跌幅=(收盤價/前收價-1)*100%',
  dealnum double DEFAULT NULL COMMENT '成交筆數',
  pre_close double DEFAULT NULL COMMENT '證券在交易日所在指定週期的首個前收盤價',
  chg double DEFAULT NULL COMMENT '漲跌=收盤價-前收價',
  swing double DEFAULT NULL COMMENT '振幅=[(最高價-最低價)/前收盤價]*100%',
  vwap double DEFAULT NULL COMMENT '均價=成交金額/成交量',
  adj_factor double DEFAULT NULL COMMENT 'Ext=X0*X1*...*Xt-1*Xt  Ext爲T日分紅復權因子  X0=1  Xt=Pt-1/Pext,其中Pext爲T日前收盤價,Pt-1爲T日前一個交易日收盤價。',
  close2 double DEFAULT NULL COMMENT ' 收盤價,該指標支持定點復權,當復權方式選擇爲定點復權時,復權基期傳入有效;否則無效。',
  turn double DEFAULT NULL COMMENT '換手率=成交量/流通股本*100%',
  free_turn double DEFAULT NULL COMMENT ' 換手率(自由流通股本)=成交量/自由流通股本*100%',
  ev double DEFAULT NULL COMMENT '上市公司的股權公平市場價值。對於一家多地上市公司,區分不同類型的股份價格和股份數量分別計算類別市值,然後加總',
  mkt_cap_ard double DEFAULT NULL COMMENT '按指定證券價格乘指定日總股本計算上市公司在該市場的估值。該總市值爲計算PE、PB等估值指標的基礎指標。暫停上市期間或退市後該指標不計算。',
  pe_ttm double DEFAULT NULL COMMENT '分子=最近交易日收盤價*最新普通股總股數分母=歸屬母公司股東的淨利潤(TTM)*最近交易日轉換匯率(記帳本位幣轉換爲交易幣種)返回=分子/分母',
  val_pe_deducted_ttm double DEFAULT NULL COMMENT '扣非後的市盈率(TTM)=總市值/前推12個月扣除非經常性損益後的淨利潤',
  pe_lyr double DEFAULT NULL COMMENT ' 每股股價爲每股收益的倍數。可回測的估值指標。  總市值2/歸屬母公司股東淨利潤(LYR) 注: 1、總市值2=指定日證券收盤價*指定日當日總股本2、B股涉及匯率轉換',
  pb_lf double DEFAULT NULL COMMENT '普通股每股市價爲每股淨資產的倍數。 總市值2/指定日最新公告股東權益(不含少數股東權益)注: 1、總市值2=指定日證券收盤價*指定日當日總股本2、B股涉及匯率轉換',
  pb_mrq double DEFAULT NULL COMMENT '每股股價爲每股淨資產的倍數。可回測的估值指標。總市值2/歸屬母公司股東的權益(MRQ)如財務報表幣種與市值幣種不同,則財務報表數據按報告期截止日匯率轉換爲市值幣種。',
  ps_ttm double DEFAULT NULL COMMENT '分子=最近交易日收盤價*最新普通股總股數 ;分母=銷售收入(TTM)*最近交易日轉換匯率(記帳本位幣轉換爲交易幣種); 返回=分子/分母',
  ps_lyr double DEFAULT NULL COMMENT '每股股價爲每股營業收入(LYR)的倍數。可回測的估值指標。總市值2/營業收入(LYR) 注:1、總市值2=指定日證券收盤價*指定日當日總股本 2、B股涉及匯率轉換',
  dividendyield2 double DEFAULT NULL COMMENT '股息率,也稱股票獲利率,是近12個月分配給股東的股息佔股價的百分比。',
  pcf_ocf_ttm double DEFAULT NULL COMMENT '每股股價爲每股經營現金流(TTM)的倍數。可回測的估值指標。總市值2/經營現金淨流量TTM ',
  pcf_ncf_ttm double DEFAULT NULL COMMENT '分子=最近交易日收盤價*最新普通股總股數 ;分母=現金及現金等價物淨增加額(TTM)*最近交易日轉換匯率(記帳本位幣轉換爲交易幣種);返回=分子/分母',
  pcf_ocflyr double DEFAULT NULL COMMENT ' 每股股價爲每股經營現金流(LYR)的倍數。可回測的估值指標。總市值2/市現率(經營現金流LYR) 注:  1、總市值2=指定日證券收盤價*指定日當日總股本  2、B股涉及匯率轉換',
  pcf_ncflyr double DEFAULT NULL COMMENT '每股股價爲每股淨現金流(LYR)的倍數。可回測的估值指標。總市值2/現金淨流量(LYR) 注: 1、總市值2=指定日證券收盤價*指定日當日總股本  2、B股涉及匯率轉換',
  trade_status varchar(100) DEFAULT NULL COMMENT '指定日該證券的市場交易狀態,如正常交易、停牌。注:但日期參數爲最新時,指最新的已收盤交易日。',
  oi double DEFAULT NULL COMMENT '持倉量',
  oi_chg double DEFAULT NULL COMMENT ' 持倉量變化',
  pre_settle double DEFAULT NULL COMMENT ' 前結算價',
  settle double DEFAULT NULL COMMENT '結算價',
  chg_settlement double DEFAULT NULL COMMENT '漲跌(結算價)',
  pct_chg_settlement double DEFAULT NULL COMMENT '漲跌幅(結算價)',
  lastradeday_s date DEFAULT NULL COMMENT ' 表示某證券有交易的最新交易日期。',
  last_trade_day date DEFAULT NULL COMMENT '表示某證券所在市場的最新一個交易日期。',
  rel_ipo_chg double DEFAULT NULL COMMENT '相對發行價漲跌=指定交易日收盤價-首發價格',
  rel_ipo_pct_chg double DEFAULT NULL COMMENT ' 相對發行價漲跌幅=[(指定交易日收盤價-首發價格)/首發價格]*100% 注:復權計算方法參見“日行情/收盤價”',
  susp_reason varchar(200) DEFAULT NULL COMMENT '證券於某交易日停牌的原因。',
  close3 double DEFAULT NULL COMMENT '指定交易日的收盤價,若無成交則返回爲空。',
  data_source varchar(100) NOT NULL DEFAULT 'Wind' COMMENT '數據來源',
  created_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建日期',
  updated_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新日期',
  UNIQUE KEY idx_code_date (stock_code,trade_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `invest`.`stock_daily_data` 
CHANGE COLUMN `index1` `index` BIGINT(20) NOT NULL ;
————————————————
版權聲明:本文爲CSDN博主「yuzhucu」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/yuzhucu/article/details/54241034

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章