首页 文章 精选 留言 我的

精选列表

搜索[Python],共10000篇文章
优秀的个人博客,低调大师

【Python量化数据工程实战 #05】多源数据怎么合?行情+基本面+公告的统一时间轴

你回测策略的时候,是不是经常遇到这种尴尬: - K线里明明涨得好好的,一查当天发布了业绩预减公告——**你根本没把公告算进去**。 - 想做个"季报超预期"策略,但季度利润表的日期和日线对不上,**不知道该填到哪一天**。 - 行情、财务、公告三个数据源各拉各的,最后靠 Excel 手动 VLOOKUP,**一改数据源全崩**。 这篇文章给你一套**多源合并的标准做法**:用 pandas 的 `merge_asof` 把不同频率、不同来源的数据,严丝合缝地对到同一天。读完你能直接跑通一段代码,把行情、季度利润、公司公告合成一张宽表。 ## 本文你将得到什么 1. 日频行情 + 季频利润 + 事件型公告的**三层合并方案** 1. `merge_asof` 前向填充的正确用法(90% 的人第一次都用错方向) 1. 一个可直接运行的完整脚本,输出统一时间轴的 DataFrame 1. 多源合并的 3 个常见坑:时区、非交易日、重复公告 ## 场景:三只数据源,三种节奏 做量化策略时,你面对的数据天然是"不同步"的: |**数据源**|**频率**|**时间戳**|**示例**| | --- | --- | --- | --- | |日线行情|日频|每个交易日|开盘、收盘、成交量| |季度利润|季频|季度末|营业收入、净利润| |公司公告|事件型|公告发布日|业绩预告、股东大会| **核心问题**:季报的截止日期是 9 月 30 日,但实际披露可能在 10 月 25 日;公告发布日可能是周末(非交易日)。如何把这三张表合到**同一个交易日时间轴**上? ## 代码实战:三源合一 下面这段代码演示完整的合并流程。证书使用官方演示证书,你可以直接复制运行: ```javascript from mairui import Client import pandas as pd client = Client("LICENCE-66D8-9F96-0C7F0FBCD073") code = "600519" # 1) 日线行情(日频) raw_hist = client.stock_history(code, lt=60, dividend='n') df_hist = pd.DataFrame(raw_hist) df_hist['t'] = pd.to_datetime(df_hist['t']) df_hist = df_hist.sort_values('t') # 2) 季度利润(季频) raw_profit = client.company_quarter_profit(code) df_profit = pd.DataFrame(raw_profit) df_profit['date'] = pd.to_datetime(df_profit['date']) df_profit = df_profit.sort_values('date') # 3) 公司公告(事件型) raw_ann = client.stock_announcement(code, lt=20) df_ann = pd.DataFrame(raw_ann) df_ann['t'] = pd.to_datetime(df_ann['t']) # === 第一层合并:季报 → 日线(前向填充) === # 策略逻辑:用"最近一期已披露财报"填充每个交易日 df_merged = pd.merge_asof( df_hist[['t', 'o', 'c', 'h', 'l', 'v']], df_profit[['date', 'profit', 'income']].rename(columns={'date': 't'}), on='t', direction='backward' # 关键:backward = 用最近的过去值填充 ) # === 第二层合并:公告 → 日线(当日计数) === # 注意:这里必须用 merge,不能用 merge_asof! df_ann_daily = df_ann.groupby('t').size().reset_index(name='ann_count') df_merged = pd.merge(df_merged, df_ann_daily, on='t', how='left') df_merged['ann_count'] = df_merged['ann_count'].fillna(0).astype(int) # 输出结果 print(df_merged.tail(10)[['t', 'c', 'profit', 'income', 'ann_count']]) ``` 运行后你会看到类似这样的输出: ```javascript t c profit income ann_count 2025-11-18 11.59 4,609,700.00 10,066,800.00 0 2025-11-19 11.80 4,609,700.00 10,066,800.00 0 2025-11-24 11.60 4,609,700.00 10,066,800.00 2 2025-12-01 11.69 4,609,700.00 10,066,800.00 5 ``` 每一行是一个交易日,"profit" 和 "income" 是该日适用的最新季度数据,"ann_count" 是当天发布的公告数量。 ## 关键细节:为什么公告不能用 merge_asof? 季报用 `merge_asof(..., direction='backward')` 是正确的,因为**一季度的财务数据在整季度都有效**,可以前向填充。 但公告完全不同:10 月 15 日发了 3 条公告,**这 3 条只属于 10 月 15 日**,不能传播到 10 月 16 日。如果你误用 `merge_asof`,10 月 16 日也会显示 "3 条公告"——这是致命的逻辑错误。 **正确做法**:公告用 `pd.merge(..., how='left')` 严格按日匹配,无公告则填 0。 ## 3 个常见坑 ### 坑 1:时区不一致导致 merge 失败 有些数据源返回 UTC,有些返回本地时间。合并前统一做一次: ```javascript df['t'] = pd.to_datetime(df['t']).dt.tz_localize(None) ``` ### 坑 2:公告日在非交易日(周末/节假日) 如果公告发布在周六,`pd.merge` 会匹配不到交易日。处理方案: ```javascript # 把公告日映射到下一个交易日(简化版) trading_days = set(df_hist['t']) df_ann['t'] = df_ann['t'].apply( lambda d: d if d in trading_days else min([t for t in trading_days if t > d], default=d) ) ``` ### 坑 3:除权除息日导致价格 discontinuity 合并后的行情如果直接做收益率计算,除权日会出现假跳空。下一篇文章会专门讲**复权处理**。 ## 小结 多源合并的核心就两步: 1. **低频 → 高频**:用 `merge_asof(..., direction='backward')` 前向填充 1. **事件 → 高频**:用 `pd.merge(..., how='left')` 严格按日匹配 掌握这两个模式,行情、财务、公告、研报、宏观数据都能统一到一个时间轴上,策略的数据底座才算真正搭好。 **下篇预告**:行情合并完了,但除权除息日价格断崖怎么办?前复权和后复权到底该用哪个?#06 带你手动算一遍复权因子,搞懂回测数据准备的最佳实践。 --- ## 免责声明 本文仅供技术学习交流,不构成任何投资建议。市场有风险,决策需谨慎。 ## 代码与文档 更多接口文档和 SDK 使用示例,可查阅官方文档:[https://github.com/MaiRuiApi/mairui](https://github.com/MaiRuiApi/mairui)

优秀的个人博客,低调大师

23、 Python快速开发分布式搜索引擎Scrapy精讲—craw母版l创建自动爬虫文件—以及 scrapy item loader机制

转: http://www.bdyss.cn http://www.swpan.cn 用命令创建自动爬虫文件 创建爬虫文件是根据scrapy的母版来创建爬虫文件的 scrapy genspider -l查看scrapy创建爬虫文件可用的母版 Available templates:母版说明 basic 创建基础爬虫文件 crawl 创建自动爬虫文件 csvfeed 创建爬取csv数据爬虫文件 xmlfeed 创建爬取xml数据爬虫文件 创建一个基础母版爬虫,其他同理 scrapy genspider -t 母版名称 爬虫文件名称 要爬取的域名创建一个基础母版爬虫,其他同理如:scrapy genspider -tcrawllagou www.lagou.com 第一步,配置items.py接收数据字段 default_output_processor = TakeFirst()默认利用ItemLoader类,加载items容器类填充数据,是列表类型,可以通过TakeFirst()方法,获取到列表里的内容 input_processor = MapCompose(预处理函数)设置数据字段的预处理函数,可以是多个函数 #-*-coding:utf-8-*- #Defineherethemodelsforyourscrapeditems # #Seedocumentationin: #http://doc.scrapy.org/en/latest/topics/items.html #items.py,文件是专门用于,接收爬虫获取到的数据信息的,就相当于是容器文件 importscrapy fromscrapy.loader.processorsimportMapCompose,TakeFirst fromscrapy.loaderimportItemLoader#导入ItemLoader类也就加载items容器类填充数据 classLagouItemLoader(ItemLoader):#自定义Loader继承ItemLoader类,在爬虫页面调用这个类填充数据到Item类 default_output_processor=TakeFirst()#默认利用ItemLoader类,加载items容器类填充数据,是列表类型,可以通过TakeFirst()方法,获取到列表里的内容 deftianjia(value):#自定义数据预处理函数 return'叫卖录音网'+value#将处理后的数据返给Item classLagouItem(scrapy.Item):#设置爬虫获取到的信息容器类 title=scrapy.Field(#接收爬虫获取到的title信息 input_processor=MapCompose(tianjia),#将数据预处理函数名称传入MapCompose方法里处理,数据预处理函数的形式参数value会自动接收字段title ) 第二步,编写自动爬虫与利用ItemLoader类加载items容器类填充数据 自动爬虫Rule()设置爬虫规则 参数: LinkExtractor()设置url规则 callback='回调函数名称' follow=True 表示在抓取页面继续深入 LinkExtractor()对爬虫获取到的url做规则判断处理 参数: allow= r'jobs/' 是一个正则表达式,表示符合这个url格式的,才提取 deny= r'jobs/' 是一个正则表达式,表示符合这个url格式的,不提取抛弃掉,与allow相反 allow_domains= www.lagou.com/ 表示这个域名下的连接才提取 deny_domains= www.lagou.com/ 表示这个域名下的连接不提取抛弃 restrict_xpaths= xpath表达式 表示可以用xpath表达式限定爬虫只提取一个页面指定区域的URL restrict_css= css选择器,表示可以用css选择器限定爬虫只提取一个页面指定区域的URL tags= 'a' 表示爬虫通过a标签去寻找url,默认已经设置,默认即可 attrs= 'href' 表示获取到a标签的href属性,默认已经设置,默认即可 * 利用自定义Loader类继承ItemLoader类,加载items容器类填充数据 *ItemLoader()实例化一个ItemLoader对象来加载items容器类,填充数据,如果是自定义Loader继承的ItemLoader同样的用法 参数: 第一个参数:要填充数据的items容器类注意加上括号, 第二个参数:response* ItemLoader对象下的方法: add_xpath('字段名称','xpath表达式')方法,用xpath表达式获取数据填充到指定字段 add_css('字段名称','css选择器')方法,用css选择器获取数据填充到指定字段 add_value('字段名称',字符串内容)方法,将指定字符串数据填充到指定字段 load_item()方法无参,将所有数据生成,load_item()方法被yield后数据被填充items容器指定类的各个字段 爬虫文件 #-*-coding:utf-8-*- importscrapy fromscrapy.linkextractorsimportLinkExtractor fromscrapy.spidersimportCrawlSpider,Rule fromadc.itemsimportLagouItem,LagouItemLoader#导入items容器类,和ItemLoader类 classLagouSpider(CrawlSpider):#创建爬虫类 name='lagou'#爬虫名称 allowed_domains=['www.luyin.org']#起始域名 start_urls=['http://www.luyin.org/']#起始url rules=( #配置抓取列表页规则 Rule(LinkExtractor(allow=('ggwa/.*')),follow=True), #配置抓取内容页规则 Rule(LinkExtractor(allow=('post/\d+.html.*')),callback='parse_job',follow=True), ) defparse_job(self,response):#回调函数,注意:因为CrawlS模板的源码创建了parse回调函数,所以切记我们不能创建parse名称的函数 #利用ItemLoader类,加载items容器类填充数据 item_loader=LagouItemLoader(LagouItem(),response=response) item_loader.add_xpath('title','/html/head/title/text()') article_item=item_loader.load_item() yieldarticle_item items.py文件与爬虫文件的原理图 【转载自:http://www.lqkweb.com】

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册