日线数据是股票每日收盘后的信息。这块数据不用实时抓取,所以并不占用宝贵的交易时间的资源。于是我们抓取完数据后直接往切片后的数据库中保存。(转载请指明出于breaksoftware的csdn博客)

抓取日线数据

我们先要获取今天有交易信息的股票代码。因为存在股票停牌的情况,所以不需要这类股票信息

    def _get_all_share_ids(self):date_info = time.strftime('%Y_%m_%d')trade_table_name = "trade_info_%s" % (date_info)share_ids = fetch_data.get_data(fetch_data.select_db("daily_temp", trade_table_name, ["share_id"],{}, pre = "distinct"))return share_ids

然后通过股票ID从股票基本信息表中获取股票代码和市场类型等数据

    def _get_all_share_ids_market_type(self):share_ids = self._get_all_share_ids()ids = []for share_id in share_ids:ids.append(share_id[0])share_ids = fetch_data.get_data(fetch_data.select_db("stock_db", "share_base_info", ["share_id", "market_type"],{"share_id":[ids, "in"]}))return share_ids

然后就是抓取和保存数据

class update_stock_daily_info(job_base):def __init__(self):passdef run(self):share_id_market_type = self._get_all_share_ids_market_type()for id_market_type in share_id_market_type:share_id = id_market_type[0]market_type = id_market_type[1]self._query_save_data(share_id, market_type)           LOG_INFO("run update_stock_daily_info")

这次我们数据从网易抓取。这儿要非常感谢网易,它提供一个通过指定起始和截止日期的接口拉取历史日线数据。如果起始和截止选择今天,则拉取的是今天的数据。

    def _get_data(self, market_type, id, start_time, end_time):url_format = """http://quotes.money.163.com/service/chddata.html?code=%d%s&start=%s&end=%s&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;PCHG;TURNOVER;VOTURNOVER;VATURNOVER"""url = url_format % (market_type, id, start_time, end_time)res = fetch_data.get_data(fetch_data.query_http(url))#res = res.decode("gbk").encode("utf-8")return res

最开始时,我们是一条数据都没有的,于是我们选择从1990年1月1日开始。之后我们有数据了,则从有数据的最后一天开始算起。

    def _get_start_time(self, share_id, table_name):stock_conn_manager_obj = stock_conn_manager()conn_name = stock_conn_manager_obj.get_conn_name(share_id)last_time = fetch_data.get_data(fetch_data.select_db(conn_name, table_name, ["time"], {}, extend="order by time desc limit 1"))if len(last_time) > 0:last_day = last_time[0][0]tz = pytz.timezone('Asia/Shanghai')last_day_obj = datetime.datetime.fromtimestamp(last_day, tz)while True:next_day_obj = last_day_obj + datetime.timedelta(days = 1)if next_day_obj.weekday() < 5:breaklast_day_obj = next_day_objtime_str = next_day_obj.strftime("%Y%m%d")else:time_str = "19900101"return time.mktime(time.strptime(time_str, '%Y%m%d'))

获取一个区间的数据后,我们通过正则表达式对结果进行拆分

    def _filter_data(self, data):data = data.replace("None", "0")filter_data = fetch_data.get_data(fetch_data.regular_split("quotes_money_163", data))if len(filter_data) > 0:del filter_data[0]useful_data = []for item in filter_data:if int(item[-2]) == 0:continuetime_str = item[0]time_int = time.mktime(time.strptime(time_str,'%Y-%m-%d'))item.insert(0, time_int)del item[2]del item[2]useful_data.append(item)return useful_data

最后将数据保存到对应的表中

    def _save_data(self, share_id, table_name, data):into_db_columns = ["time","time_str","today_close","today_high","today_low","today_open","yesterday_close","pchg","turnover_rate","volume","turnover"]columns_count = len(into_db_columns)for item in data:if len(item) != columns_count:LOG_INFO("%s length is not match for column length %d" %(str(item), columns_count))continuedel itemif 0 == len(data):returnstock_conn_manager_obj = stock_conn_manager()conn = stock_conn_manager_obj.get_conn(share_id)conn.insert_data(table_name, into_db_columns, data)

计算均线数据

均线数据按类型分可以分为成交量均线和价格均线。按时间分可以分为5日、10日、20日、30日、60日、90日、120日、180日和360日均线。

为了方便计算,我引入了talib库

pip install TA-Lib  -i http://pypi.douban.com/simple

首先获取所有股票代码以便之后枚举

class update_stock_daily_average_info(job_base):def __init__(self):passdef run(self):share_ids = self._get_all_share_ids()for share_id_item in share_ids:share_id = share_id_item[0]self._update_average(share_id)           LOG_INFO("run update_stock_daily_average_info")def _get_all_share_ids(self):date_info = time.strftime('%Y_%m_%d')trade_table_name = "trade_info_%s" % (date_info)share_ids = fetch_data.get_data(fetch_data.select_db("daily_temp", trade_table_name, ["share_id"],{}, pre = "distinct"))return share_ids

然后查询每支股票最后一次计算均线的日期。判断规则就是查看价格5日均线值是否为0。因为均线计算量非常大,所以我们不能野蛮的全部重算。每次都要基于上次计算成果进行增量计算。

    def _get_ma_empty_start_time(self, share_id, table_name):stock_conn_manager_obj = stock_conn_manager()conn_name = stock_conn_manager_obj.get_conn_name(share_id)last_time = fetch_data.get_data(fetch_data.select_db(conn_name, table_name, ["time"], {"close_ma5":[0, "="]}, extend="order by time asc limit 1"))if len(last_time) > 0:last_day = last_time[0][0]tz = pytz.timezone('Asia/Shanghai')last_day_obj = datetime.datetime.fromtimestamp(last_day, tz)time_str = last_day_obj.strftime("%Y%m%d")return time.mktime(time.strptime(time_str, '%Y%m%d'))else:return 0

因为我们代码中最多分析180日均线数据,所以日期要从上面函数得到的日前前推180日;如果之前没有180日数据,则返回最早的那天。如果是新股,则返回当日。

    def _get_start_time(self, share_id, table_name, ma_empty_start_time):stock_conn_manager_obj = stock_conn_manager()conn_name = stock_conn_manager_obj.get_conn_name(share_id)last_time = fetch_data.get_data(fetch_data.select_db(conn_name, table_name, ["time"], {"time":[ma_empty_start_time, "<="]}, extend="order by time desc limit 180"))if len(last_time) > 0:last_day = last_time[-1][0]tz = pytz.timezone('Asia/Shanghai')last_day_obj = datetime.datetime.fromtimestamp(last_day, tz)time_str = last_day_obj.strftime("%Y%m%d")return time.mktime(time.strptime(time_str, '%Y%m%d'))else:return ma_empty_start_time

下一步就是计算各个日期的均值

    def _get_ma_data(self, ori_data, periods):ret_data = {}float_data = [float(x) for x in ori_data]for period in periods:data = talib.MA(numpy.array(float_data), timeperiod = period)data_list = data.tolist()data_list = self._filter_data(data_list)ret_data["%d" % period] = data_listreturn ret_data

然后将计算结果保存到数组中并保存

    def _calc_average_data(self, share_id, table_name):ma_empty_start_time_int = self._get_ma_empty_start_time(share_id, table_name)if ma_empty_start_time_int == 0:return []start_time_int = self._get_start_time(share_id, table_name, ma_empty_start_time_int)stock_info = self._get_close_volume(share_id, table_name, start_time_int)periods = [5, 10, 20, 30, 60, 90, 120, 150, 180]#periods = [90, 180]close_data = self._get_ma_data(stock_info["close"], periods)volume_data = self._get_ma_data(stock_info["volume"], periods)if len(stock_info["time"]) == len(close_data["180"]) and len(close_data["180"]) == len(volume_data["180"]):passelse:LOG_WARNING("calc %s daily average error" % share_id)returninfos = []data_len = len(stock_info["time"])for index in range(data_len):info = {}time_int = stock_info["time"][index]if time_int < ma_empty_start_time_int:continueinfo["time"] = time_intfor period in periods:info["close_ma%s" % period] = close_data["%s" % period][index]info["volume_ma%s" % period] = volume_data["%s" % period][index]infos.append(info)return infosdef _filter_data(self, data):for index in range(len(data)):if math.isnan(data[index]):data[index] = 0.01else:breakreturn datadef _save_data(self, share_id, table_name, data):if len(data) < 2:return stock_conn_manager_obj = stock_conn_manager()conn = stock_conn_manager_obj.get_conn(share_id)conn.update(table_name, data, ["time"])

计算除权后均线数据

之前算的那些均值理论上来说是没什么用的!因为没有除权!这是我在对比我的数据和同花顺的数据之后得出的。于是只能再改改。

基本思路是要计算一个因子,因子=前一日数据中收盘价/今日数据中昨日收盘价。然后把除权日之前的价格都“乘以”该因子得出向后复权的价格,相应的把除权日之前的成交量都“除以”该因子得出向后复权的成交量。这样就会导致整个表进行一次更新(从后向前)。

有意思的是同花顺将成交量也“乘以”该因子,其实这个算法是错误的。举个例子,比如昨日股票收盘10元,成交量100股,则成交金额是1000元。今天除权,于是拉取数据中昨日的收盘价是5元。这样相当于单股价值缩水一半。那么因子是5/10=0.5。那么向后复权计算,昨日的股票收盘价是10*0,5=5元。成交量应该是100/0,5=200股。这样昨日的成交金额是5*200=1000。但是同花顺的算法昨日成交量100*0.5=50股,这明显是错误的。

最后贴上向后复权的算法

    def _dividend_ori_data(self, share_id, from_table, to_table, start_time, compare = ">", yesterday_close = 0):ori_data = self._get_daily_info(share_id, from_table, start_time, compare)if 0 == len(ori_data):return 0if ori_data[0][6] == yesterday_close:return 0ex_dividend_ori = []pre_div_value = 1for item in ori_data:if 0 == yesterday_close:ex_dividend_ori.append(item)yesterday_close = item[6]continueif len(ex_dividend_ori) > 0:yesterday_close = ex_dividend_ori[-1][6]ori_close = item[2]if ori_close == 0 or yesterday_close == 0:div_value = pre_div_valueelse:if yesterday_close == ori_close:ex_dividend_ori.append(item)continuediv_value = yesterday_close/ori_closepre_div_value = div_valueex_dividend_ori.append([item[0], item[1], item[2] * div_value, item[3] * div_value,item[4] * div_value,item[5] * div_value,item[6] * div_value,item[7],item[8],item[9] / div_value,item[10]])stock_conn_manager_obj = stock_conn_manager()conn = stock_conn_manager_obj.get_conn(share_id)if from_table != to_table:conn.insert_data(to_table, self._table_keys, ex_dividend_ori)else:for info_value in ex_dividend_ori:infos = {}for index in range(len(self._table_keys)):infos[self._table_keys[index]] = info_value[index]conn.insert_onduplicate(to_table, infos, ["time"])conn.insert_onduplicate(to_table, {"close_ma5":0, "time":ex_dividend_ori[-1][0]}, ["time"])last_yesterday_close = ex_dividend_ori[-1][6]return last_yesterday_close        

码农技术炒股之路——抓取日线数据、计算均线和除权数据相关推荐

  1. 码农技术炒股之路——抓取股票基本信息、实时交易信息、主力动向信息

    从本节开始,我们开始介绍各个抓取和备份业务.(转载请指明出于breaksoftware的csdn博客) 因为我们数据库很多,数据库中表也很多,所以我们需要一个自动检测并创建数据库和表的功能.在< ...

  2. 码农技术炒股之路——任务管理器

    系统任务和普通任务都是通过任务管理器调度的.它们的区别是:系统任务在程序运行后即不会被修改,而普通任务则会被修改.(转载请指明出于breaksoftware的csdn博客) 为什么要有这样的设计?因为 ...

  3. 码农技术炒股之路——数据库管理器、正则表达式管理器

    我选用的数据库是Mysql.选用它是因为其可以满足我的需求,而且资料多.因为作为第三方工具,难免有一些配置问题.所以本文也会讲解一些和Mysql配置及开发相关的问题.(转载请指明出于breaksoft ...

  4. 码农技术炒股之路——配置管理器、日志管理器

    配置管理器和日志管理器是项目中最为独立的模块.我们可以很方便将其剥离出来供其他Python工程使用.文件的重点将是介绍Python单例和logging模块的使用.(转载请指明出于breaksoftwa ...

  5. 码农技术炒股之路——实时交易信息、主力动向信息分库备份

    一般来说,一个股票信息应该保存在一张表中.但是由于我机器资源限制,且我希望尽快频率的抓取数据.所以每天我将所有股票的实时交易信息放在daily_temp库中的一个以日期命名的表中.主力动向信息也是如此 ...

  6. 抓取网络源码python_使用Python进行网络抓取的新手指南

    抓取网络源码python 有很多很棒的书可以帮助您学习Python,但是谁真正读了这些A到Z? (剧透:不是我). 接下来是我的第一个Python抓取项目指南. 假定的Python和HTML知识很少. ...

  7. 如何抓取天猫和淘宝的运营数据?

    淘宝为了屏蔽网络爬虫对自身数据(例如商品价格.月销量.收藏量.评价.月成交记录等等)的抓取,往往是采取一种名叫Ajax的技术,在网页加载完成后,再次加载这些数据,所以通用的网络爬虫抓取技术对抓取淘宝的 ...

  8. 学校铃声Java_java_java多线程抓取铃声多多官网的铃声数据,一直想练习下java多线程抓取数 - phpStudy...

    java多线程抓取铃声多多官网的铃声数据 一直想练习下java多线程抓取数据. 有天被我发现,铃声多多的官网(http://www.shoujiduoduo.com/main/)有大量的数据. 通过观 ...

  9. Python 抓取软科中国大学排名首页数据

    文章目录 利用requests.BeautifulSoup.xlwings库抓取软科中国大学排名首页数据 (1)软科中国大学排名 (2)调用requests模块中get方法,get方法包括header ...

最新文章

  1. Appium安装(Mac版)
  2. 工厂方法模式适用场景
  3. [剑指offer][JAVA]面试题第[21]题[调整数组顺序使奇数位于偶数面前][双指针]
  4. FormsAuthenticationTicket基于forms的验证
  5. 机器学习实战(十二)降维(PCA、SVD)
  6. php hashids思路,使用composer添加hashids加密数字
  7. Spring Boot 国际化踩坑指南
  8. SwiftUI 控件
  9. matlab冲激激励,实验一 阶跃响应与冲激响应.doc
  10. 互动媒体技术——《代码本色》习作二:向量
  11. 实现一个脚本引擎(燕良译)- -
  12. 击鼓游戏-第10届蓝桥杯Scratch省赛真题第7题
  13. org.dom4j.DocumentException: Error on line 1 of document : Content is not allowed in prolog. Nested
  14. 强化学习、GAN与多巴胺对撞:阿里AI 智能体认知研讨会干货
  15. Windows光盘映像刻录机设置---Windows资源管理器
  16. BSON和JSON的区别
  17. Simulink搭建三相PWM整流器过程
  18. ExtremeTable 使用简介
  19. Altium Designer 鼠标移动到元件高亮显示连接网络
  20. bootstrap4侧边栏_如何使用纯CSS和Bootstrap 4构建多个堆叠式粘性侧边栏

热门文章

  1. Python OpenCV GrabCut进行前景分割和提取
  2. 线性代数--矩阵、向量
  3. 电子产品如何使用IAP方式升级程序
  4. 力扣(LeetCode)刷题,简单题(第3期)
  5. android实现长截屏,Android实现全屏截图或长截屏功能
  6. python爬图片教程_python爬去妹子网整个图片资源教程(最详细版)
  7. 基于octree的空间划分及搜索操作
  8. Redis在CentOS 6.8中的安装方法,JAVA初级使用Redis连接池
  9. 在Ubuntu 14.04 64bit上升级安装ATS 5.3.2/6.1.1实录
  10. vim学习笔记(三)