1. 为什么我最终放弃了手动更新股票数据
做股票复盘这件事,我坚持了快六年。前三年一直用最笨的办法:每天收盘后打开行情软件,把自选股的收盘价、成交量、涨跌幅一个个敲进Excel表格里。十几只股票还好,后来自选池扩到五六十只,每天光录入就要花掉四十分钟,还经常敲错数字,第二天对着K线图复盘时发现数据对不上,又得回头翻记录找问题。
后来我试过用Excel自带的“从网页获取数据”功能,把行情网站的表格直接抓进来。这个方法确实省了手工录入的力气,但问题也很明显:网页结构一改,抓取就报错;有些网站做了反爬处理,刷新几次就返回空值;更麻烦的是历史数据,网页上通常只显示最近几十个交易日,想拉三年前的日线数据根本拿不到。
真正让我下决心换方案的,是一次季度复盘。我需要把过去两年每只股票的周线数据整理出来做对比分析,结果发现之前手工录入的数据里有将近百分之十五的缺失和错误。那一刻我意识到,数据源头的可靠性比分析技巧重要得多。于是我开始认真研究Power Query这个工具,花了两周时间搭好一套自动获取和刷新股票历史数据的流程,一直用到现在,稳定运行了三年多。
这套方案的核心思路很简单:用Power Query连接公开的财经数据接口,把股票代码、日期范围作为参数传进去,自动拉取历史行情数据,存到Excel表格里。以后每次打开文件,点一下“全部刷新”,最新数据就会自动更新进来。整个过程不需要写VBA,不需要装插件,Excel自带的功能就能完成。适合所有用Excel做股票复盘、量化回测、持仓跟踪的普通投资者,哪怕你之前完全没接触过Power Query,跟着操作也能搭起来。
2. 整体设计思路与工具选型考量
2.1 为什么选Power Query而不是VBA或Python
市面上获取股票历史数据的方法大致有三类:一是用VBA写爬虫脚本,二是用Python的pandas库配合财经数据接口,三是用Excel内置的Power Query。这三种我都实际用过,说说各自的优缺点。
VBA的优势是灵活,想怎么处理数据都行,但缺点也很致命:代码调试麻烦,一旦网站结构变化或者接口调整,排查问题要花大量时间;而且VBA脚本在不同版本的Excel上兼容性参差不齐,我遇到过在Windows上跑得好好的宏,换到Mac版Excel就报错的情况。另外VBA处理大量数据时性能下降明显,拉取几千行日线数据还能应付,数据量再大就卡得不行。
Python方案功能最强,pandas处理数据效率高,财经数据接口也很丰富。但它有两个门槛:一是需要安装Python环境和相关库,对没有编程基础的人来说配置过程容易劝退;二是数据获取和Excel展示之间需要额外的导出步骤,没法做到在Excel里一键刷新。如果你本身就在用Python做量化分析,那直接用Python没问题,但如果你的主战场是Excel,为了拉数据再搭一套Python环境,有点杀鸡用牛刀。
Power Query恰好卡在中间:它内置于Excel 2016及以上版本,不需要额外安装;操作以图形界面为主,学习成本低;支持参数化查询,可以把股票代码和日期范围做成变量;最关键的是,它和Excel表格是无缝集成的,刷新操作就在Excel里完成,不需要切换工具。性能方面,Power Query底层用的是M语言引擎,处理几万行数据毫无压力,我实测拉取五十只股票十年的日线数据,总共约十二万行,刷新一次大概二十秒左右。
提示:Mac版Excel从2019版本开始支持Power Query,但功能比Windows版少一些。如果你用的是Mac,建议先确认Excel版本,部分高级连接器可能不可用。不过本文用到的Web.Contents函数在Mac版上是可以正常工作的。
2.2 数据源的选择标准与接口逻辑
选数据源这件事,我踩过的坑最多。最早我用的是某财经网站的手机端接口,返回的是JSON格式数据,解析起来方便,但用了不到半年接口就变了,返回结构完全不一样,之前写的解析步骤全部作废。后来我总结出选数据源的几个标准:
第一,接口要稳定,至少两年内没有大的变动。怎么判断?看这个接口是不是被广泛使用,社区里有没有人持续维护。如果一个接口只有少数人在用,一旦提供方调整,你连求助的地方都没有。
第二,返回格式要规整。优先选返回JSON或CSV的接口,这两种格式结构清晰,Power Query解析起来方便。尽量避免返回HTML的接口,因为HTML里夹杂大量样式标签,提取数据需要做复杂的文本处理,而且网页改版后解析逻辑很容易失效。
第三,数据字段要齐全。至少要有日期、开盘价、最高价、最低价、收盘价、成交量这几个基本字段。如果还能提供复权因子、换手率、成交额就更好了,方便后续做更细致的分析。
第四,访问频率限制要宽松。有些接口每分钟只允许请求几次,如果你要拉取多只股票的数据,很容易触发限制。选那种对个人用户比较友好的接口,或者支持批量查询的接口。
基于这些标准,我最终选用的是一类公开的财经数据接口,它们通常以JSON格式返回数据,字段命名规范,而且支持通过URL参数指定股票代码和日期范围。具体接口地址这里不展开,因为接口可能会变动,更重要的是掌握方法:你可以在财经数据网站上找到类似的接口,或者用一些开源财经数据项目提供的API。关键是把接口的调用方式、参数格式、返回结构搞清楚,然后在Power Query里做对应的解析。
2.3 整体架构:从接口到Excel的完整链路
整套方案的架构分四层:
最底层是数据源接口,负责提供原始的股票行情数据。这一层是外部依赖,我们控制不了,但可以通过合理的错误处理来应对接口异常。
第二层是Power Query查询,负责调用接口、解析返回数据、做初步的清洗和类型转换。这一层是整个方案的核心,所有的逻辑都在这里实现。
第三层是Excel表格,Power Query处理好的数据会加载到表格里,你可以像操作普通Excel表格一样对它进行排序、筛选、做透视表。
最上层是刷新机制,通过Excel的“全部刷新”功能,一键更新所有查询的数据。如果你需要定时自动刷新,还可以配合Windows的任务计划程序来实现。
这四层各司其职,耦合度低。接口变了,只需要改Power Query里的URL和解析步骤;展示方式变了,只需要调整Excel表格的格式;刷新频率变了,只需要改任务计划的设置。这种分层设计的好处是,任何一层出问题,排查范围都局限在那一层,不会牵一发而动全身。
3. 核心细节解析与实操要点
3.1 Power Query的启动与基本界面认知
打开Excel,在“数据”选项卡里找到“获取数据”按钮,下拉菜单里有一项“来自其他源”,再往下能看到“空查询”。点击“空查询”,就会打开Power Query编辑器。这个编辑器是一个独立的窗口,左边是查询列表,中间是数据预览区,右边是“应用的步骤”面板,顶部是功能区。
如果你是第一次用Power Query,建议先花十分钟熟悉一下界面布局。左边查询列表里显示的是当前工作簿里所有的查询,你可以新建多个查询,分别对应不同的数据源或不同的处理逻辑。中间的数据预览区会显示当前步骤处理后的数据样子,每一步操作都会实时反映在这里。右边的“应用的步骤”面板记录了你对数据做的所有操作,从源开始,每一步都按顺序列出来。这个面板非常重要,因为它让你可以回溯每一步的操作,如果某一步做错了,点一下那一步就能看到当时的数据状态,方便排查问题。
注意:Power Query编辑器里的操作是“声明式”的,也就是说你做的每一步操作都会被记录下来,而不是直接修改原始数据。原始数据始终保持不变,所有变换都是在这个基础上叠加的。这种设计的好处是,你可以随时删除或调整中间的某一步,而不影响其他步骤。
3.2 用Web.Contents函数调用数据接口
在Power Query里调用Web接口,核心函数是Web.Contents。它的基本用法是传入一个URL,返回接口的响应内容。比如:
= Web.Contents("https://api.example.com/stock/history?code=000001&start=2020-01-01&end=2024-12-31")这个函数返回的是二进制内容,需要根据接口返回的格式做进一步解析。如果接口返回的是JSON,就用Json.Document函数把二进制内容转成Power Query可以识别的记录或列表:
= Json.Document(Web.Contents("https://api.example.com/stock/history?code=000001&start=2020-01-01&end=2024-12-31"))这里有几个实操要点需要特别注意:
第一,URL里的参数最好用变量代替,不要写死在字符串里。比如股票代码和日期范围,应该做成参数,这样后续要拉取不同股票或不同时间段的数据时,只需要改变量的值,不用改URL。在Power Query里,你可以通过“管理参数”功能新建参数,然后在URL里引用这些参数。
第二,如果接口需要指定请求头,比如User-Agent或者Accept,可以在Web.Contents的第二个参数里传入一个记录:
= Web.Contents( "https://api.example.com/stock/history", [ Query = [ code = "000001", start = "2020-01-01", end = "2024-12-31" ], Headers = [ #"User-Agent" = "Mozilla/5.0", Accept = "application/json" ] ] )这种写法比直接把参数拼在URL里更规范,也更容易维护。Query字段里的参数会被自动拼接到URL的查询字符串里,Headers字段里的内容会作为请求头发送。
第三,如果接口返回的数据量很大,可能会超时。Power Query默认的超时时间比较短,你可以在Web.Contents里通过Timeout选项来延长:
= Web.Contents( "https://api.example.com/stock/history", [ Query = [code = "000001", start = "2020-01-01", end = "2024-12-31"], Timeout = #duration(0, 0, 5, 0) ] )这里的#duration(0, 0, 5, 0)表示5分钟超时,四个参数分别是天、小时、分钟、秒。对于拉取大量历史数据的场景,建议把超时设长一点,避免因为网络波动导致刷新失败。
3.3 解析JSON返回结构并提取数据表
接口返回的JSON结构通常有两种形式:一种是直接返回一个数组,每个元素是一条记录;另一种是返回一个对象,数据藏在某个字段里。你需要先看清楚返回结构,再决定怎么解析。
假设返回的是这样的结构:
{ "code": 0, "msg": "success", "data": [ {"date": "2024-01-02", "open": 10.5, "high": 10.8, "low": 10.3, "close": 10.6, "volume": 1234567}, {"date": "2024-01-03", "open": 10.6, "high": 11.0, "low": 10.5, "close": 10.9, "volume": 2345678} ] }解析步骤是这样的:先用Json.Document把二进制转成记录,然后取data字段,得到一个列表,再用Table.FromList把列表转成表格:
let Source = Json.Document(Web.Contents("https://api.example.com/stock/history?code=000001&start=2024-01-01&end=2024-12-31")), DataList = Source[data], ToTable = Table.FromList(DataList, Splitter.SplitByNothing(), null, null, ExtraValues.Error), ExpandRecord = Table.ExpandRecordColumn(ToTable, "Column1", {"date", "open", "high", "low", "close", "volume"}, {"date", "open", "high", "low", "close", "volume"}) in ExpandRecord这段代码的逻辑是:先把JSON转成记录,取出data字段(这是一个列表),把列表转成单列表格,然后展开记录列,把每个字段拆成独立的列。Table.ExpandRecordColumn这个函数很关键,它能把嵌套的记录结构展开成扁平的表格。
如果返回的JSON结构更复杂,比如data字段里还有嵌套的对象,那就需要多展开几次。Power Query的“应用的步骤”面板会记录每一步,你可以逐步展开,直到得到想要的扁平表格。
提示:在解析JSON之前,建议先用一个简单的查询把原始返回内容展示出来,确认结构后再写解析逻辑。可以在Power Query里新建一个空查询,输入= Json.Document(Web.Contents(...)),然后点“到表”或者直接查看记录结构。这样能避免因为结构理解错误导致解析失败。
3.4 数据类型转换与字段规范化
从接口拿到的数据,类型往往是不对的。比如日期可能是字符串,价格可能是文本,成交量可能是科学计数法。加载到Excel之前,必须把类型转正确,否则后续做计算时会出错。
在Power Query里,转换类型有两种方式:一是点击列标题左边的类型图标,直接选择目标类型;二是用Table.TransformColumnTypes函数批量转换。推荐用第二种方式,因为它是显式声明,步骤面板里能看到,方便回溯。
= Table.TransformColumnTypes( ExpandRecord, { {"date", type date}, {"open", type number}, {"high", type number}, {"low", type number}, {"close", type number}, {"volume", Int64.Type} } )这里有几个细节需要注意:
日期字段用type date,不要用type datetime,因为日线数据只需要日期,不需要时间部分。如果接口返回的日期格式不是标准的“年-月-日”,比如是“20240102”这种紧凑格式,需要先用Date.FromText配合格式字符串来转换:
= Table.TransformColumns( ExpandRecord, {{"date", each Date.FromText(Text.Insert(Text.Insert(_, 4, "-"), 7, "-")), type date}} )价格字段用type number,Power Query会自动处理小数。成交量字段用Int64.Type,因为成交量通常是整数,用Int64可以避免大数溢出。如果接口返回的成交量是带单位的字符串,比如“123万”,那就需要先做文本替换再转数字。
字段命名也建议规范化。接口返回的字段名可能是英文缩写,比如“o”“h”“l”“c”“v”,可读性差。可以在Power Query里重命名列,改成“开盘价”“最高价”“最低价”“收盘价”“成交量”这样的中文名,方便后续在Excel里做分析。
3.5 参数化查询:让股票代码和日期范围可配置
参数化是这套方案能否复用的关键。如果每次拉取不同股票的数据都要改代码,那效率太低了。正确的做法是把股票代码、开始日期、结束日期做成参数,在Excel表格里维护一个参数表,Power Query读取这个表来获取参数值。
具体操作是这样的:在Excel里新建一个工作表,命名为“参数”,在A列放股票代码,B列放开始日期,C列放结束日期。然后把这个区域转成表格(选中区域,按Ctrl+T),命名为“股票参数表”。
在Power Query里,新建一个查询,从Excel表格获取数据,得到参数表。然后新建一个自定义函数,把股票代码和日期范围作为输入参数,返回该股票的历史数据。最后用这个自定义函数对参数表里的每一行做调用,把结果合并成一张大表。
自定义函数的写法如下:
(股票代码 as text, 开始日期 as date, 结束日期 as date) => let Source = Json.Document( Web.Contents( "https://api.example.com/stock/history", [ Query = [ code = 股票代码, start = Date.ToText(开始日期, "yyyy-MM-dd"), end = Date.ToText(结束日期, "yyyy-MM-dd") ] ] ) ), DataList = Source[data], ToTable = Table.FromList(DataList, Splitter.SplitByNothing(), null, null, ExtraValues.Error), ExpandRecord = Table.ExpandRecordColumn(ToTable, "Column1", {"date", "open", "high", "low", "close", "volume"}, {"date", "open", "high", "low", "close", "volume"}), ChangeType = Table.TransformColumnTypes(ExpandRecord, {{"date", type date}, {"open", type number}, {"high", type number}, {"low", type number}, {"close", type number}, {"volume", Int64.Type}}), AddCode = Table.AddColumn(ChangeType, "股票代码", each 股票代码, type text) in AddCode这个函数接收三个参数,返回处理好的数据表,并且在最后加了一列“股票代码”,方便后续区分不同股票的数据。
然后在主查询里,读取参数表,对每一行调用这个函数:
let ParamTable = Excel.CurrentWorkbook(){[Name="股票参数表"]}[Content], InvokeFunction = Table.AddColumn(ParamTable, "历史数据", each 获取股票历史数据([股票代码], [开始日期], [结束日期])), ExpandData = Table.ExpandTableColumn(InvokeFunction, "历史数据", {"date", "open", "high", "low", "close", "volume", "股票代码"}) in ExpandData这样,你只需要在参数表里增删行,刷新后就能自动拉取对应股票的数据。想加一只新股票,就在参数表里加一行,填上代码和日期范围,点刷新,数据就进来了。
注意:如果参数表里有很多行,Power Query会逐行调用接口,这个过程可能比较慢。建议一次不要放太多股票,分批拉取。另外,有些接口对请求频率有限制,如果发现刷新时报错,可能是触发了频率限制,需要降低请求速度或者换接口。
4. 完整实操流程与关键环节实现
4.1 从零搭建:新建工作簿与参数表
第一步,新建一个Excel工作簿,命名为“股票数据自动更新.xlsx”。这个工作簿将作为整个方案的主文件,所有的查询、参数表、数据表都放在这里面。
第二步,新建一个工作表,命名为“参数”。在这个表里设置三列:A列标题为“股票代码”,B列标题为“开始日期”,C列标题为“结束日期”。然后在下面填入你要跟踪的股票。比如:
| 股票代码 | 开始日期 | 结束日期 |
|---|---|---|
| 000001 | 2020-01-01 | 2024-12-31 |
| 600519 | 2020-01-01 | 2024-12-31 |
| 300750 | 2020-01-01 | 2024-12-31 |
填好后,选中A1:C4区域,按Ctrl+T转成表格,在弹出的对话框里勾选“我的表格有标题”,点击确定。然后在上方“表格设计”选项卡里,把表格名称改为“股票参数表”。
提示:日期格式建议用“年-月-日”的标准格式,避免用“2020/1/1”这种可能被Excel识别为文本的格式。如果输入后Excel自动变成了其他格式,可以选中单元格,右键设置单元格格式,选择“日期”,再选“yyyy-mm-dd”格式。
4.2 创建自定义函数查询
第三步,打开Power Query编辑器。在Excel的“数据”选项卡里,点击“获取数据”->“来自其他源”->“空查询”。这会打开Power Query编辑器,并创建一个名为“查询1”的空查询。
第四步,在Power Query编辑器里,点击“主页”选项卡下的“高级编辑器”。这会弹出一个窗口,里面显示当前查询的M代码。把里面的内容全部删掉,替换成上面3.5节里的自定义函数代码。注意把URL替换成你实际使用的接口地址。点击“完成”后,把这个查询重命名为“获取股票历史数据”。
重命名的方法是:在左边的查询列表里右键点击查询名,选择“重命名”,输入新名称。或者在右侧的“查询设置”面板里,找到“名称”属性,直接修改。
第五步,测试自定义函数是否能正常工作。在查询列表里右键点击“获取股票历史数据”,选择“调用函数”。在弹出的对话框里,输入一个测试用的股票代码和日期范围,点击确定。如果一切正常,你会看到一个新的查询,里面包含了拉取到的数据。检查一下数据是否完整,字段类型是否正确。如果报错,根据错误信息排查问题,常见的问题包括URL错误、接口返回结构变化、网络连接问题等。
测试通过后,把测试查询删掉,只保留自定义函数查询。
4.3 创建主查询并加载数据
第六步,再新建一个空查询,在高级编辑器里输入主查询的代码(见3.5节)。这段代码会读取“股票参数表”,对每一行调用自定义函数,然后把结果展开成一张大表。
第七步,点击“主页”选项卡下的“关闭并上载至”。在弹出的对话框里,选择“表”,然后选择一个位置来放置数据。建议新建一个工作表,命名为“历史数据”,把数据加载到那里。点击确定后,Power Query会把处理好的数据加载到Excel表格里。
加载完成后,你会看到“历史数据”工作表里有一张表格,包含了所有股票的日线数据,字段包括日期、开盘价、最高价、最低价、收盘价、成交量、股票代码。表格的行数取决于你拉取了多少只股票、多长时间的数据。
注意:如果数据量很大,加载过程可能需要一些时间。加载完成后,Excel表格会自动套用表格格式,你可以根据需要调整列宽、设置数字格式、添加筛选按钮等。
4.4 刷新机制与自动化设置
第八步,测试刷新功能。在“历史数据”工作表里,右键点击表格任意位置,选择“刷新”。或者在上方“数据”选项卡里,点击“全部刷新”。Power Query会重新执行所有查询,从接口拉取最新数据,更新到表格里。
如果刷新成功,你会看到表格里的数据更新了。如果刷新失败,Excel会弹出错误提示,告诉你哪个查询出了问题。常见的刷新失败原因包括:网络连接中断、接口地址变更、接口返回结构变化、请求频率超限等。针对不同的原因,需要采取不同的处理措施。
第九步,设置自动刷新。如果你希望每天收盘后自动刷新数据,可以用Windows的任务计划程序来实现。具体做法是:创建一个新的基本任务,设置触发时间为每天下午四点(或者你习惯的复盘时间),操作选择“启动程序”,程序路径填Excel的安装路径,参数填工作簿的完整路径。这样到了设定时间,Excel会自动打开工作簿并刷新数据。
不过任务计划程序调用Excel刷新有个前提:工作簿里需要有一段VBA代码,在打开时自动执行刷新。按Alt+F11打开VBA编辑器,在“ThisWorkbook”模块里输入:
Private Sub Workbook_Open() ThisWorkbook.RefreshAll ThisWorkbook.Save ThisWorkbook.Close End Sub这段代码的作用是:工作簿打开时自动刷新所有查询,刷新完成后保存并关闭。配合任务计划程序,就能实现无人值守的自动更新。
提示:如果你的Excel版本不支持Power Query,或者你用的是Mac版Excel,自动刷新的设置方式会有所不同。Mac版Excel没有任务计划程序,但可以用日历应用或者第三方自动化工具来触发刷新。另外,Mac版Excel的VBA支持也不如Windows版完整,部分代码可能需要调整。
4.5 数据验证与异常处理
第十步,验证数据的准确性。拉取到数据后,不要急着做分析,先花几分钟检查一下数据质量。检查的内容包括:日期范围是否覆盖了你指定的区间、有没有缺失的交易日、价格数据是否在合理范围内、成交量是否为正数、不同股票的数据是否混在一起。
我一般会做几个快速检查:用Excel的筛选功能看看日期列有没有空值,用条件格式标出价格异常的行(比如收盘价大于1000或者小于0.1),用数据透视表统计每只股票的数据行数,看看是否大致符合交易日数量。
如果发现数据有问题,回到Power Query编辑器里排查。常见的问题和解决方法:
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| 日期列显示为文本 | 接口返回的日期格式不标准 | 用Date.FromText配合格式字符串转换 |
| 价格列有科学计数法 | 数据类型被识别为文本 | 用Table.TransformColumnTypes转成number |
| 数据行数明显偏少 | 接口有分页限制 | 检查接口文档,看是否需要传分页参数 |
| 刷新时报401错误 | 接口需要认证 | 检查是否需要传API Key或Token |
| 刷新时报429错误 | 请求频率超限 | 降低请求速度,或分批拉取 |
| 部分股票数据为空 | 股票代码格式不对 | 检查代码是否需要加市场前缀 |
注意:接口返回的数据偶尔会有异常值,比如某天的收盘价是0或者成交量是负数。这些异常值可能是接口本身的bug,也可能是数据传输过程中的错误。在Power Query里可以用Table.SelectRows过滤掉明显异常的行,或者在Excel里用条件格式标出来,人工复核。
5. 常见问题与排查技巧实录
5.1 刷新时提示“找不到数据源”怎么办
这是最常见的问题之一。表现是点击刷新后,Excel弹出对话框说“找不到数据源”或者“无法连接到远程服务器”。原因通常有三种:一是网络连接有问题,二是接口地址变了,三是接口暂时不可用。
排查步骤:首先确认网络是否正常,可以打开浏览器访问一下接口地址,看看能不能返回数据。如果浏览器能访问但Power Query不行,可能是Power Query的凭据设置有问题。在Power Query编辑器里,点击“数据源设置”,找到对应的数据源,检查凭据类型是否正确。有些接口需要匿名访问,有些需要Windows凭据或者API Key。
如果接口地址变了,需要回到Power Query编辑器里,找到Web.Contents那一步,把URL更新成新的地址。如果接口暂时不可用,可以等一段时间再试,或者换一个备用接口。
5.2 数据刷新后格式乱了怎么恢复
Power Query加载数据到Excel时,会自动套用表格格式。但有时候刷新后,你之前设置的列宽、数字格式、条件格式会丢失。这是因为Power Query在刷新时会重建表格,覆盖掉手动设置的格式。
解决方法有两个:一是把格式设置放在Power Query里做,比如在加载前用Table.TransformColumnTypes设置好类型,用Table.RenameColumns改好列名,这样刷新后格式不会变。二是把数据加载到“仅创建连接”,然后用Excel的“数据透视表”或者“公式”来引用查询结果,这样格式设置就不会被覆盖。
我个人的做法是:把原始数据加载到一张表里,不做任何格式设置;然后另建一张表,用公式引用原始数据,在第二张表上做格式设置和分析。这样刷新时只影响第一张表,第二张表的格式不受影响。
5.3 接口返回的数据有缺失怎么补全
有时候接口返回的数据不完整,比如某只股票某几天的数据缺失,或者某天的成交量是空值。这种情况在免费接口里比较常见,因为数据提供方可能没有覆盖所有交易日,或者接口本身有bug。
处理缺失数据的方法取决于缺失的程度和原因。如果只是偶尔缺一两天,可以在Excel里手动补上,或者用前后两天的平均值填充。如果缺失比较多,建议换一个数据源,或者用多个数据源交叉验证。
在Power Query里,可以用Table.FillDown或者Table.FillUp来填充空值,但这两个函数只适用于有规律的数据。对于股票数据,更稳妥的做法是保留空值,在分析时用Excel的IFERROR或者IF函数来处理。
提示:不要轻易用平均值填充股票价格数据,因为股票价格波动很大,平均值可能严重偏离实际。如果缺失的是收盘价,可以用当天的开盘价和最高最低价来估算,但要在分析时注明这是估算值。
5.4 拉取大量数据时刷新太慢怎么优化
如果你跟踪的股票很多,或者拉取的时间范围很长,刷新可能会很慢。我实测过,拉取五十只股票十年的日线数据,大概需要二十秒左右。如果股票数量增加到两百只,刷新时间可能超过一分钟。
优化刷新速度的方法有几个:一是减少不必要的数据列,只拉取你真正需要的字段,比如只要日期、收盘价、成交量,不要开盘价和最高最低价。二是缩小日期范围,只拉取最近两三年的数据,历史数据可以单独拉一次存起来,不用每次刷新都拉。三是分批拉取,把股票分成几组,每组一个查询,刷新时可以并行执行,比单个查询拉所有股票要快。
另外,如果接口支持批量查询,尽量用批量查询代替逐只查询。有些接口允许一次传多个股票代码,返回所有股票的数据,这样只需要一次请求就能拿到所有数据,比逐只请求快得多。
5.5 换电脑后查询报错怎么迁移
Power Query查询是保存在Excel工作簿里的,换电脑后只要工作簿文件在,查询就在。但有时候换电脑后刷新会报错,原因通常是新电脑上的Excel版本不同,或者凭据设置没有同步。
迁移步骤:首先确认新电脑上的Excel版本是否支持Power Query,Windows版Excel 2016及以上都支持,Mac版Excel 2019及以上支持。然后打开工作簿,在Power Query编辑器里检查数据源设置,重新输入凭据。如果接口需要API Key,确保Key没有过期。最后测试刷新,如果报错,根据错误信息逐一排查。
如果新电脑上的Excel版本较低,部分Power Query函数可能不可用。比如Table.ExpandRecordColumn在旧版本里可能没有,需要用其他函数替代。建议尽量保持Excel版本一致,或者把查询逻辑简化,只用最基础的函数。
5.6 常见问题速查表
| 问题 | 排查方向 | 快速解决 |
|---|---|---|
| 刷新报错“找不到数据源” | 网络、接口地址、凭据 | 浏览器测试接口,检查数据源设置 |
| 数据格式刷新后丢失 | 格式设置位置 | 把格式设置放在Power Query里,或用公式引用 |
| 数据缺失 | 接口覆盖范围 | 换数据源,或手动补全 |
| 刷新太慢 | 数据量、请求方式 | 减少列、缩小日期范围、分批拉取 |
| 换电脑后报错 | Excel版本、凭据 | 检查版本,重新设置凭据 |
| 日期显示为文本 | 日期格式 | 用Date.FromText转换 |
| 价格显示为科学计数法 | 数据类型 | 用Table.TransformColumnTypes转number |
| 请求频率超限 | 接口限制 | 降低请求速度,分批拉取 |
6. 我在这套方案上踩过的坑和总结的技巧
这套方案我用了三年多,中间踩过不少坑,也积累了一些文档里不会写的经验。分享几个我觉得最有价值的:
第一个坑是接口的日期格式。我最早用的一个接口,日期返回的是“20240102”这种紧凑格式,我一开始没注意,直接当文本加载了,结果在Excel里排序全是乱的。后来用Date.FromText配合Text.Insert来转换,才把日期转正确。这个教训是:拿到数据后第一件事就是检查字段类型,不要假设接口返回的格式是你期望的。
第二个坑是请求频率。有段时间我跟踪的股票比较多,刷新时经常报429错误。后来我把股票分成三组,每组间隔几秒再请求,问题就解决了。如果你也遇到类似问题,可以在Power Query里用Function.InvokeAfter来加延迟,或者把查询拆成多个,手动分批刷新。
第三个坑是数据源的稳定性。我用过的一个接口,用了大半年一直很稳定,突然有一天返回结构变了,之前写的解析步骤全部失效。从那以后,我养成了一个习惯:每次刷新后都快速扫一眼数据,看看行数、字段、数值范围有没有异常。如果发现异常,第一时间排查,不要等到做分析时才发现数据有问题。
第四个技巧是关于参数表的维护。我一开始把股票代码和日期范围写在Power Query代码里,每次加股票都要改代码,很麻烦。后来改成从Excel表格读取参数,加股票只需要在表格里加一行,刷新就行。这个改动虽然小,但大大提升了日常使用的便利性。
第五个技巧是关于数据存储。Power Query加载的数据是存在Excel工作簿里的,工作簿会随着数据量增加而变大。如果你的数据量很大,建议把历史数据存到单独的工作簿里,主工作簿只保留最近几个月的数据。或者用Power Query的“仅创建连接”选项,把数据加载到数据模型里,而不是工作表里,这样可以减小文件体积。
最后分享一个我常用的检查方法:每次刷新后,用数据透视表快速统计一下每只股票的数据行数和日期范围。如果某只股票的行数明显偏少,或者日期范围不对,就说明数据可能有问题。这个方法花不了几秒钟,但能帮你及时发现数据异常,避免在错误的数据上做分析。