Python獲取股票歷史數據和收盤數據的代碼實現

http://casey.blog.51cto.com/9994043/1707905python

各類股票軟件,例如通達信、同花順、大智慧,均可以實時查看股票價格和走勢,作一些簡單的選股和定量分析,可是若是你想作更復雜的分析,例如迴歸分析、關聯分析等就有點捉襟見肘,因此最好可以獲取股票歷史及實時數據並存儲到數據庫,而後再經過其餘工具,例如SPSS、SAS、EXCEL或者其餘高級編程語言鏈接數據庫獲取股票數據進行定量分析,這樣就能實現更多目的了。mysql

      爲此,首先須要找到能夠獲取股票數據的接口,新浪、雅虎、騰訊等都有接口能夠實時獲取股票數據,歷史數據選擇了雅虎接口,收盤數據選擇了騰訊接口。sql

    (1)項目結構數據庫

wKioL1YyHhfTV5ZQAAE6J6--0Gg957.jpg

    (2)數據庫鏈接池編程

     connectionpool.py
多線程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#-*- coding: UTF-8 -*- 
'''
create a connection pool
'''
from  DBUtils  import  PooledDB
import  MySQLdb
import  string
maxconn  =  30             #最大鏈接數
mincached  =  10            #最小空閒鏈接
maxcached  =  20           #最大空閒鏈接
maxshared  =  30           #最大共享鏈接
connstring = "root#root#127.0.0.1#3307#pystock#utf8"  #數據庫地址
dbtype  =  "mysql"                    #選擇mysql做爲存儲數據庫
def  createConnectionPool(connstring, dbtype):
     db_conn  =  connstring.split( "#" );
     if  dbtype = = 'mysql' :
         try :
             pool  =  PooledDB.PooledDB(MySQLdb, user = db_conn[ 0 ],passwd = db_conn[ 1 ],host = db_conn[ 2 ],port = string.atoi(db_conn[ 3 ]),db = db_conn[ 4 ],charset = db_conn[ 5 ], mincached = mincached,maxcached = maxcached,maxshared = maxshared,maxconnections = maxconn)
             return  pool
         except  Exception, e:
             raise  Exception, 'conn datasource Excepts,%s!!!(%s).' % (db_conn[ 2 ], str (e))
             return  None
pool  =  createConnectionPool(connstring, dbtype)

 
    (3)數據庫操做app

     DBOperator.py
編程語言

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#-*- coding: UTF-8 -*- 
''' 
Created on 2015-3-13
@author: Casey
'''
import  MySQLdb
from  stockmining.stocks.setting  import  LoggerFactory
import  connectionpool
class  DBOperator( object ):
     
     def  __init__( self ):
         self .logger  =  LoggerFactory.getLogger( 'DBOperator' )
         #self.conn = None
         
     def  connDB( self ):
         #單鏈接
         #self.conn=MySQLdb.connect(host="127.0.0.1",user="root",passwd="root",db="pystock",port=3307,charset="utf8")  
         #鏈接池中獲取鏈接
         self .conn = connectionpool.pool.connection()
         return  self .conn
     def  closeDB( self ):
         if ( self .conn ! =  None ):
             self .conn.close()  
     
     
     def  insertIntoDB( self , table,  dict ):
         try :
             if ( self .conn ! =  None ):
                 cursor  =  self .conn.cursor()
             else :
                 raise  MySQLdb.Error( 'No connection' )
            
             sql  =  "insert into "  +  table  +  "("
             param  =  []
             for  key  in  dict :
                 sql  + =  key  +  ','
                 param.append( dict .get(key))
             param  =  tuple (param)
             sql  =  sql[: - 1 +  ") values("
             for  in  range ( len ( dict )):
                 sql  + =  "%s,"
             sql  =  sql[: - 1 +  ")"
         
             self .logger.debug(sql  %  param)    
             =  cursor.execute(sql, param)  
             self .conn.commit()  
             cursor.close()  
         except  MySQLdb.Error,e:
             self .logger.error( "Mysql Error %d: %s"  %  (e.args[ 0 ], e.args[ 1 ]))
             self .conn.rollback()
     def  execute( self , sql):
         try :
             if ( self .conn ! =  None ):
                 cursor  =  self .conn.cursor()
             else :
                 raise  MySQLdb.Error( 'No connection' )
             
             =  cursor.execute(sql)
             return  n
         except  MySQLdb.Error,e:
             self .logger.error( "Mysql Error %d: %s"  %  (e.args[ 0 ], e.args[ 1 ]))
  
     def  findBySQL( self , sql):
         try :
             if ( self .conn ! =  None ):
                 cursor  =  self .conn.cursor()
             else :
                 raise  MySQLdb.Error( 'No connection' )
             
             cursor.execute(sql)
             rows  =  cursor.fetchall() 
             return  rows
         except  MySQLdb.Error,e:
             self .logger.error( "Mysql Error %d: %s"  %  (e.args[ 0 ], e.args[ 1 ]))
     
     def  findByCondition( self , table, fields, wheres):
         try :
             if ( self .conn ! =  None ):
                 cursor  =  self .conn.cursor()
             else :
                 raise  MySQLdb.Error( 'No connection' )
             
             sql  =  "select " 
             for  field  in  fields:
                 sql  + =  field  +  ","
             sql  =  sql[: - 1 +  " from "  +  table  +  " where "   
             
             param  =  []
             values  =  ''
             for  where  in  wheres:
                 sql  + =  where.key  +  "='%s' and " 
                 param.append(where.value)
             param  =  tuple (param)   
             self .logger.debug(sql)    
             
             =  cursor.execute(sql[: - 5 %  param)  
             self .conn.commit()  
             cursor.close()  
         except  MySQLdb.Error,e:
             self .logger.error( "Mysql Error %d: %s"  %  (e.args[ 0 ], e.args[ 1 ]))

     
    (4)日誌工具

   LoggerFactory.py
fetch

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
#-*- coding: UTF-8 -*- 
'''
Created on 2015-3-11
@author: Casey
'''
import  logging
import  time
'''
傳入名稱
'''
def  getLogger(name):
         now  =  time.strftime( '%Y-%m-%d %H:%M:%S' )
         
         logging.basicConfig(
             level     =  logging.DEBUG,
             format    =  now  + " : "  +  name  +  ' LINE %(lineno)-4d  %(levelname)-8s %(message)s' ,
             datefmt   =  '%m-%d %H:%M' ,
             filename  =   "d:\\stocks\stock.log" ,
             filemode  =  'w' );
                     
         console  =  logging.StreamHandler();
         console.setLevel(logging.DEBUG);
         formatter  =  logging.Formatter(name  +  ': LINE %(lineno)-4d : %(levelname)-8s %(message)s' );
         console.setFormatter(formatter);
         
         logger  =  logging.getLogger(name)
         logger.addHandler(console); 
         return  logger
     
if  __name__  = =  '__main__' :
     getLogger( "www" ).debug( "www" )


   (5)獲取股票歷史數據

      採用雅虎的接口:http://ichart.yahoo.com/table.csv?s=<string>&a=<int>&b=<int>&c=<int>&d=<int>&e=<int>&f=<int>&g=d&ignore=.csv

    參 數:s — 股票名稱 

           a — 起始時間,月 

           b — 起始時間,日 

           c — 起始時間,年 

           d — 結束時間,月 

           e — 結束時間,日 

           f — 結束時間,年 

           g— 時間週期。

          (必定注意月份參數,其值比真實數據-1。如須要9月數據,則寫爲08。)

    示例 查詢浦發銀行2010.09.25 – 2010.10.8之間日線數據

    http://ichart.yahoo.com/table.csv?s=600000.SS&a=08&b=25&c=2010&d=09&e=8&f=2010&g=d

  返回:

     Date,Open,High,Low,Close,Volume,Adj Close

    2010-09-30,12.37,12.99,12.32,12.95,76420500,12.95

    2010-09-29,12.20,12.69,12.12,12.48,79916400,12.48

    2010-09-28,12.92,12.92,12.57,12.58,63988100,12.58

    2010-09-27,13.00,13.02,12.89,12.94,43203600,12.94


   由於數據量比較大,須要跑好久,因此也能夠考慮多線程模式來獲取相關數據,單線程模式:

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#-*- coding: UTF-8 -*- 
'''
Created on 2015-3-1
@author: Casey
'''
import  urllib
import  re
import  sys
from  setting  import  params
import  urllib2
from  db  import  *
dbOperator  =  DBOperator()
table  =  "stock_quote_yahoo"
'''查找指定日期股票流量'''
def  isStockExitsInDate(table, stock, date):
     sql  =  "select * from "  +  table  +  " where code = '%d' and date='%s'"  %  (stock, date)
     =  dbOperator.execute(sql) 
     if  n > =  1 :
         return  True 
     
def  getHistoryStockData(code, dataurl):
     try :
         =  urllib2.Request(dataurl)
         try :
             stdout  =  urllib2.urlopen(r, data = None , timeout = 3 )
         except  Exception,e:
             print  ">>>>>> Exception: "  + str (e)  
             return  None
         
         stdoutInfo  =  stdout.read().decode(params.codingtype).encode( 'utf-8'
         tempData  =  stdoutInfo.replace( '"' , '')
         stockQuotes  =  []
         if  tempData.find( '404' ) ! =  - 1 :  stockQuotes  =  tempData.split( "\n" )
       
         stockDetail  =  {}
         for  stockQuote  in  stockQuotes:
             stockInfo  =  stockQuote.split( "," )
             if  len (stockInfo)  = =  7  and  stockInfo[ 0 ]! = 'Date' :
                 if  not  isStockExitsInDate(table, code, stockInfo[ 0 ]):
                    stockDetail[ "date" =  stockInfo[ 0 ]
                    stockDetail[ "open" ]   =  stockInfo[ 1 ]   #開盤
                    stockDetail[ "high" ]     =  stockInfo[ 2 ]   #最高
                    stockDetail[ "low" ]     =  stockInfo[ 3 ]   #最低
                    stockDetail[ "close" =  stockInfo[ 4 ]   #收盤
                    stockDetail[ "volume" =  stockInfo[ 5 ]   #交易量
                    stockDetail[ "adj_close" =  stockInfo[ 6 #收盤adj價格
                    stockDetail[ "code" =  code         #代碼
                    dbOperator.insertIntoDB(table, stockDetail) 
         result  =  tempData
     except  Exception as err:
         print  ">>>>>> Exception: "  +  str (dataurl)  +  " "  +  str (err)
     else :
         return  result
     finally :
         None
         
def  get_stock_history():
     #滬市2005-2015歷史數據
     for  code  in  range ( 601999 602100 ):
         dataUrl  =  "http://ichart.yahoo.com/table.csv?s=%d.SS&a=01&b=01&c=2005&d=01&e=01&f=2015&g=d"  %  code
         print  getHistoryStockData(code, dataUrl )
    
     
     #深市2005-2015歷史數據
     for  code  in  range ( 1 1999 ):
         dataUrl  =  "http://ichart.yahoo.com/table.csv?s=%06d.SZ&a=01&b=01&c=2005&d=01&e=01&f=2015&g=d"  %  code
         print  getHistoryStockData(code, dataUrl)
 
     
     #中小板股票
     for  code  in  range ( 2001 2999 ):   
         dataUrl  =  "http://ichart.yahoo.com/table.csv?s=%06d.SZ&a=01&b=01&c=2005&d=01&e=01&f=2015&g=d"  %  code
         print  getHistoryStockData(code, dataUrl)
       
     
     #創業板股票
     for  code  in  range ( 300001 300400 ):
         dataUrl  =  "http://ichart.yahoo.com/table.csv?s=%d.SZ&a=01&b=01&c=2005&d=01&e=01&f=2015&g=d"  %  code
         print  getHistoryStockData(code, dataUrl)
    
         
def  main():
     "main function"
    
     dbOperator.connDB()
     get_stock_history()
     dbOperator.closeDB() 
     
if  __name__  = =  '__main__' :
     main()


     (6)獲取實時價格和現金流數據

      A:實時價格數據採用騰訊的接口:滬市:http://qt.gtimg.cn/q=sh<int>,深市:http://qt.gtimg.cn/q=sz<int>

      如獲取平安銀行的股票實時數據:http://qt.gtimg.cn/q=sz000001,會返回一個包含股票數據的字符串:

v_sz000001="51~平安銀行~000001~11.27~11.27~11.30~316703~151512~165192~11.27~93~11.26~
4352~11.25~4996~11.24~1037~11.23~1801~11.28~1181~11.29~2108~11.30~1075~11.31~1592~11.32~
1118~15:00:24/11.27/3146/S/3545407/17948|14:56:59/11.26/15/S/16890/17787|
14:56:56/11.25/404/S/454693/17783|14:56:54/11.26/173/B/194674/17780|14:56:51
/11.26/306/B/344526/17777|14:56:47/11.26/16/B/18016/17773~
20151029150142~0.00~0.00~11.36~11.25~
11.26/313557/354285045~
316703~35783~0.27~7.38~~11.36~11.25~0.98~1330.32~1612.59~1.03~12.40~10.14~";

     數據比較多,比較有用的是: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-賣五量;30-時間;31-漲跌;32-漲跌率;33-最高價;34-最低價;35-成交量(萬);38-換手率;39-市盈率;42-振幅;43-流通市值;44-總市值;45-市淨率


       B:現金流數據仍然採用騰訊接口:滬市:http://qt.gtimg.cn/q=ff_sh<int>,深市:http://qt.gtimg.cn/q=ff_sz<int>

      例如平安銀行的現金流數據http://qt.gtimg.cn/q=ff_sz000001:

v_ff_sz000001="sz000001~21162.20~24136.40~-2974.20~-8.31~14620.87~11646.65~2974.22~
8.31~35783.07~261502.0~261158.3~平安銀行~20151029~20151028^37054.20^39358.20~
20151027^39713.50^42230.70~20151026^82000.80^83689.90~20151023^81571.30^71743.10";

          比較重要的:1-主力流入;2-主力流出;3-主力淨流量;4-主力流入/主力總資金;5-散戶流入;6-散戶流出;7-散戶淨流量;8-散戶流入/散戶總資金;9-總資金流量;12-名字;13-日期


           採用多線程、數據庫鏈接池實現股票實時價格和現金流數據的獲取:

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
相關文章
相關標籤/搜索