精华内容
下载资源
问答
  • 闲了的时候还是要学一点金融知识,先不说金融懂多少,但是通过金融的目的来编程其实也还行。总之美好的一天不要浑浑噩噩的度过。我觉得都是值得回忆的美好岁月。我们都知道股票市场有很多...

          闲了的时候还是要学一点金融知识,先不说金融懂多少,但是通过金融的目的来编程其实也还行。总之美好的一天不要浑浑噩噩的度过。我觉得都是值得回忆的美好岁月。我们都知道股票市场有很多交易数据,有人亏损有人盈利。但是赚的人肯定是赚了很久了。赔的人也许会一直亏,但也可能厚积薄发。作为一只初来乍到的程序员,咋没有那种科班背景,所以很多时候唯一能派上用场的的好好学习。那么最基础的肯定需要知道基本知识吧,因为我本人是一只目的和好奇心驱动的猿,所以让我系统的学习某个专业会让我很难接受,主要是学过之后不一定能够形成系统的认知能力。可能效果总比我这样凭感觉的好的多的多。后期再看情况,先不扯这些话题。今天的目标就是记录一下我是如何获取股票数据的。没错我用的是开源的组件,没有写爬虫。因为股票数据是有专业的组织开放的api,里边比较好的是tushare和baostack。然后之前使用tushare还好,还是自从他们升级之后就需要积分了,然后发现自己的积分不够。所以我采用了baostack,但是baostack的问题是“数据不全”。其实也不是数据不全,而是获取全部股票信息的时候返回的数据总是隔三差五。让我对此产生了怀疑。纠结之下发现tushare能够获取全部股票列表,然后我把之前baostack中没有返回的股票代码作为参数调baostack其实也是能返回数据的。那么就是baostack的rs=bs.query_stock_basic()接口的问题?反正已经呵呵哒了,所以我最终采用的策略是使用tushare获取上证和深证的股票,然后调用baostack获取股票的历史交易数据并保存到文件中。

    import sys
    import tushare as ts
    import pandas as pd
    
    
    df_stock_list_all = ts.get_stock_basics()
    df_stock_list_all.reset_index(level=0, inplace=True)
    df_stock_list_all_sort_code = df_stock_list_all.sort_values('code')
    #上证股票都是600开头的
    df_stock_sh = df_stock_list_all_sort_code[df_stock_list_all_sort_code['code']>'600000']
    #深证股票最后的股票代码是300838,002中小板,300是创业板,000是主板
    df_stock_sz = df_stock_list_all_sort_code[df_stock_list_all_sort_code['code']<'300859']
    sys.path.append("libs")
    result=[]
    for i in range(0, len(df_stock_sh)):
        data = []
        data.append("sh." + df_stock_sh.iloc[i]['code'])
        data.append(df_stock_sh.iloc[i]['name'])
        # 时间处理的原因是baostack需要是YYY-MM-dd的格式
        tian=str(df_stock_sh.iloc[i]['timeToMarket'])
        timeTemp=tian[:4] + "-" + tian[4:6] + "-" + tian[6:8]
        data.append(timeTemp)
        #为了兼容之前使用的baostack的数据,这里表示退市时间
        data.append("")
        #下边两个参数也是兼容之前老代码 
        data.append(1)
        data.append(1)
        result.append(data)
    for j in range(0, len(df_stock_sz)):
        data = []
        data.append("sz." + df_stock_sz.iloc[j]['code'])
        data.append(df_stock_sz.iloc[j]['name'])
        tian= str(df_stock_sz.iloc[j]['timeToMarket'])
        timeTemp=tian[:4] + "-" + tian[4:6] + "-" + tian[6:8]
        data.append(timeTemp)
        data.append("")
        data.append(1)
        data.append(1)
        result.append(data)
    
    
    result = pd.DataFrame(result)
    result.rename(columns = {"0": "code","1":"name"})
    #header=0表示FrameDate数据中不要表头
    result.to_csv("../data/basic_tushare.csv",header=0)
    

    很快就获取了数据,数据效果还不错。后期再向mysql存储。

    获取到股票列表之后就是逐个去获取股票的每日交易信息了。这块我用的是baostack,主要还是之前使用的baostack做了一点探索,而且他们免费。所以顺势而为。

    import baostock as bs
    import pandas as pd
    import csv
    #读取刚才拉到的股票数据
    baseStockFile="../data/basic_tushare.csv"
    csvFile=open(baseStockFile,"r",encoding="UTF-8")
    reader=csv.reader(csvFile)
    
    
    def baoStackReq(code,start):
        lg=bs.login()
        print(lg)
        data=bs.query_history_k_data(code,"date,code,open,high,low,close,preclose,"
                                                 "volume,amount,adjustflag,turn,tradestatus,pctChg,peTTM,"
                                          "pbMRQ,psTTM,pcfNcfTTM,isST",start_date=start)
        targetData=[]
        while (data.error_code=="0")&data.next():
            targetData.append(data.get_row_data())
        result=pd.DataFrame(targetData,columns=data.fields)
        #这里还是不要打印了因为数据量比较大,会比较耗时间
        print(result)
        #用code作为股票交易数据的存储文件名称
        code=code.replace(".","")
        result.to_csv("../data/"+code+".csv")
    
    
    for item in reader:
        print(item)
        line=item[0]
        code=item[1]
        start=item[3]
        #排除未上市的股票
        if len(start)<10:
            continue
        baoStackReq(code,start)
    

    通过上述代码,我们就可以拉取股票了。拉取的效果。

    因为数据量比较大,所以拉取的过程比较长,大概需要1个小时多。

    除此之外,考虑到我们每次获取的数据肯定不是全部获取,我们肯定是获取我们没有的交易数据,那么如何添加到这只股票的cvs文件之后呐。我们可以使用result.to_csv("../data/"+code+".csv",mode="a")这里的mode="a"表示以追加的方式写入文件。

    后边有时间的话,会逐步写相关的文章。主要是实现数据的自动维护和k线预测。同时希望在此过程中提升自己的python编程能力。

    展开全文
  • python获取股票历史数据

    千次阅读 2015-11-02 09:50:09
    例如通达信、同花顺、大智慧,都可以实时查看股票价格和走势,做一些简单的选股和定量分析,但是如果你想做更复杂的分析,例如回归分析、关联分析等就有点捉襟见肘,所以最好能够获取股票历史及实时数据并存储到...

    各种股票软件,例如通达信、同花顺、大智慧,都可以实时查看股票价格和走势,做一些简单的选股和定量分析,但是如果你想做更复杂的分析,例如回归分析、关联分析等就有点捉襟见肘,所以最好能够获取股票历史及实时数据并存储到数据库,然后再通过其他工具,例如SPSS、SAS、EXCEL或者其他高级编程语言连接数据库获取股票数据进行定量分析,这样就能实现更多目的了。

          为此,首先需要找到可以获取股票数据的接口,新浪、雅虎、腾讯等都有接口可以实时获取股票数据,历史数据选择了雅虎接口,收盘数据选择了腾讯接口。

        (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)数据库操作

         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

    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(601999602100):
            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(11999):
            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(20012999):   
            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(300001300400):
            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
    192
    193
    194
    195
    196