Stock_Analysis_For_Quant / 均线实现

同一条均线策略,四种工具各写一遍:门槛、骨架与对不齐的地方

「把一条均线策略实现出来」这件事,在这个仓库里能做四遍:Python 侧有 Moving_Averages.ipynb 与 SMA.ipynb,R 侧有 R_Moving_Average.R,Excel 侧有 Stock_Plot_MA.xlsx 与 7 个启用宏的工作簿,Matlab 侧有 DailyReturn.m 与三个 Live Script。

但要注意一个前提:这四条路的成本完全不对等。Matlab 目录全目录只有 6 个文件,按其余三条路的预期去用它一定会失望。本页给出每一条路的最小骨架、四份结果对齐的检查表,以及按你自身条件该怎么选——所有骨架都标注为方法说明,本站在本机没有运行过 Stock_Analysis_For_Quant 里的任何文件。

核验提交 df4bd3c58d71Python 侧 213 个指标文件R 侧 162 个技术分析脚本Matlab 侧 4 个代码文件

四条实现路径的依据

Python:SMA.ipynbnotebook + pandas,取数走 yfinance,指标区共 213 个文件
R:R_Moving_Average.Rquantmod 脚本,R_Technical_Analysis 下 159 个脚本之一
Excel:7 个 .xlsm公式 + 按钮式宏,另有 Stock_Plot_MA.xlsx 等顶层工作簿
Matlab:1 个 .m + 3 个 .mlxDailyReturn / DailyStock / financial_analysis,全目录仅 6 个文件
均线策略四工具实现依据(按固定提交 df4bd3c58d71 的文件清单);示意非官方图表,Matlab 侧体量明显最小,相关步骤本站未实测。
Comparison

Stock_Analysis_For_Quant 里四工具实现同一条均线策略:逐维度对照

下表每一格都指到仓库里真实存在的文件或目录。比「哪个语言好」更实际的问题是:你手上的条件能走通哪一条。

对照维度PythonRExcelMatlab
实现依据文件Technical_Indicators/SMA.ipynb、Moving_Averages.ipynb、Golden_Death_Cross.ipynbR_Technical_Analysis/R_Moving_Average.R、R_EMA.R、R_MA_High_Low.RStock_Plot_MA.xlsx、Stock_Trend.xlsx、Excel_Stock_VBA_Macros/ 下 7 个 .xlsmDailyStock.mlx、financial_analysis.mlx、DailyReturn.m
代码形态与粒度一个指标一个 notebook,代码与图表混在同一个文件里一个方法一个脚本,纯代码、无输出缓存单元格公式 + 按钮式宏,逻辑藏在公式与 VBA 里脚本版与实时脚本版各一份,粒度最粗
数据接入yfinance(yf.Ticker('AAPL') 这类写法)quantmod::getSymbols('AAPL', ...)工作簿内自带数据快照,需自己贴新数据取数逻辑写在 Live Script 里,需自己核对
依赖与安装门槛需 Python 3 与若干库;仓库不提供依赖清单需 R 与 quantmod 等包;同样无清单只需表格软件(含宏功能),但 .xlsm 会触发宏安全提示需 Matlab(README 写 R2016a 或更新),属商业软件
指标库覆盖(全目录)指标区 213 个文件,均线类含 SMA / EMA / WMA / DEMA / TEMA / TRIMA / KAMA / Hull / ZLEMA / Guppy 等技术分析区 159 个脚本,含 R_EMA.R、R_WMA、R_Band_SMA.R、R_MA_Oscillator.R指标区只有 4 个文件,均线主要靠公式自行搭建无独立指标目录,均线需自己写
出图能力matplotlib 一类库,图与代码同源,便于复现基座绘图够用,代码短、出图快原生图表,交互好但公式改动需人工同步绘图能力完整,但本站未实测
结果可重复性高:一段代码可原样重跑(前提是自己的依赖记下来)高:同 Python,脚本粒度更小中:公式可追溯,但人工操作环节多中:依赖本机版本,未实测无法判断
更容易踩的坑库里同名指标写法不同(如 talib 与 ta 两套),混用会得到不同数值参数默认值与 Python 库不同,直接对比会出现偏差复权价与原始价混用最隐蔽;宏在工作簿里的行为不易审查样本量太小,缺少可对照的第二个实现
一个必须先说清的判断:Stock_Analysis_For_Quant 把六个工具并列展示,但按固定提交清点,均线相关的可对照实现在 Python 与 R 两侧最厚、Excel 次之、Matlab 最薄。做「四语言同题对照」时,Matlab 那一路更接近「看看别人怎么写」,而不是「有四个成熟实现可供选型」。
Rule first

先把「同一条均线策略」定义清楚:八个必须写死的口径

四份实现之所以经常对不上,绝大多数不是代码写错,而是这八项里有一项没统一。先填完这张表,再动代码。

口径项常见写法写错/不统一的后果对齐建议
用什么价收盘价;或复权后的收盘价;或典型价(高+低+收)/3四个工具对「价」的默认理解不同,均线本身就不一样在策略记录里写死「用哪一个字段」,并写清是否复权
均线类型SMA 简单平均;EMA 指数加权;WMA 加权同名「20 日均线」在两个工具里可能是不同东西写清类型与周期,例如 SMA(20) 而不是「20 日线」
周期参数短 5/10/20,长 60/120/200参数不同则信号完全不同,跨语言对比失去意义四份实现用同一组参数,并把参数写进结果文件名
信号定义短线上穿长线为买入(金叉),下穿为卖出(死叉)有的实现用「价格穿越均线」,有的用「双均线交叉」用一句话把信号写成布尔条件,四个实现照抄这一句
信号日与成交日信号当日收盘成交,或次日开盘成交次日成交会显著改变结果,也是未来函数的高发点明确写「T 日信号、T+1 成交」或「T 日收盘成交」
成本假设手续费按比例、滑点按最小变动单位不计成本的收益曲线通常明显偏高统一给出费率与滑点公式,并注明以实际费率与数据源为准
样本区间与缺失值固定起止日期;停牌或缺失日如何处理区间不同直接导致收益不可比;缺失值填充方式会改变指标四份实现共用同一份数据文件与同一段起止日期
空仓规则无信号时空仓,或始终持有「空仓」与「持有」是两种策略,不能互相对比把空仓规则写成第三种状态并明确标注
这八项不是本站发明的规范,而是把四份实现放在一起时必然会碰到的差异点。写策略记录时把这张表抄一遍,后面的对齐工作量会下降一大半——这也是回测审计页里「信号日与成交日是否分离」那一项的落地做法。
Skeletons

Python 与 R 的最小骨架:把上面八项写成代码

下面两段是方法骨架,不是 Stock_Analysis_For_Quant 里文件的原文,也没有在本站运行过。写出来是为了让你看清两种实现的形态差异:Python 侧一段 pandas 就能表达,R 侧靠 quantmod 与内置函数更短。

# Python 骨架:SMA 交叉(方法说明,未在本站运行)
import yfinance as yf, pandas as pd

px   = yf.Ticker("AAPL").history(start="2020-01-01", end="2023-12-31")
close = px["Close"]                      # 口径①:用收盘价(是否复权需自行确认)

short = close.rolling(20).mean()         # 口径②③:SMA,参数 20 / 60
long_ = close.rolling(60).mean()

signal = (short > long_).astype(int)     # 口径④:短线上穿长线为持仓状态
trade  = signal.diff().fillna(0)         # 口径⑤:T 日信号,T+1 成交需再 shift(1)

print(close.tail(), signal.sum(), trade.sum())   # 预期输出:价格尾部 + 持仓天数 + 交易次数
# R 骨架:SMA 交叉(方法说明,未在本站运行)
library(quantmod)

getSymbols("AAPL", from = "2020-01-01", to = "2023-12-31", auto.assign = TRUE)
close  <- Cl(AAPL)                       # 口径①:收盘价,系列由取数函数决定
short  <- SMA(close, n = 20)             # 口径②③:SMA,参数 20 / 60
long_  <- SMA(close, n = 60)

state  <- ifelse(short > long_, 1, 0)    # 口径④:与 Python 侧同一句条件
flip   <- diff(state)                    # 口径⑤:信号变化处才是交易发生点

tail(close); sum(state, na.rm = TRUE); sum(abs(flip), na.rm = TRUE)  # 预期输出:价格尾部 + 持仓 + 换手
骨架里的节点预期看到什么看不到时先查哪一项注意点
取数一张按日期索引的价格表,行数等于区间内交易日数网络、标的代码、起止日期格式Python 与 R 的默认复权处理不同,需显式确认
滚动均值前 19(Python)或 19 行(R)为空值,之后才有值是不是把窗口写成了 20 个「自然日」空值段不能直接参与信号判断,否则会伪造出早期信号
信号序列一条只有 0/1 的序列,与价格表等长比较方向是否写反(短线在上应为 1)写成 0/1 状态比写成「买卖点」更容易跨语言对齐
交易次数远小于持仓天数的一个整数是否把每日的持仓状态当成了交易交易次数是后续套成本的关键输入,必须先跑通
两语言结果对比持仓天数与换手次数应非常接近复权、时区、缺失日处理三处差异完全相等并不现实,量级一致即可先往下走
为什么给骨架而不给现成文件:Stock_Analysis_For_Quant 没有依赖清单,直接照搬某个 notebook 很容易卡在库上。先用自己的骨架跑通「取数→均线→信号→统计」四步,再去对照它的实现,排查成本会低很多。这里的骨架是方法说明,不代表仓库里那两个文件的实际写法。
Excel

Excel 这一路:公式可追溯,但 7 个启用宏的工作簿要留意

Excel 侧做均线不靠库,靠公式与宏。好处是每一步都能肉眼追溯,代价是人工环节多、批量处理不便。下表把这一路要碰到的文件列清楚。

文件形态大概做什么注意点
Excel_Stock/Stock_Plot_MA.xlsx顶层工作簿均线绘制与趋势可视化的表格实现数据是写入工作簿的快照,换成新标的要自己替换数据区
Excel_Stock/Excel_Stock_VBA_Macros/Stock_Calculate_Daily_Returns.xlsm启用宏的工作簿用宏批量算日收益,是均线信号的前置计算需要启用宏并接受安全提示
Excel_Stock/Excel_Stock_VBA_Macros/Stock_Functions_DailyReturns.xlsm启用宏的工作簿把日收益计算封装成可复用函数与上一个文件功能相邻,注意区分哪个是你需要的
Excel_Stock/Excel_Stock_VBA_Macros/Stock_Button_Sheets.xlsm 与 Stock_Button_Sheets_Simple.xlsx宏 + 普通工作簿各一按钮式整理工作表结构同一功能的宏版与普通版并存,别混用
Excel_Stock/Excel_Stock_VBA_Macros/Stock_Button_Sort_Symbols.xlsm 与 Stock_Button_Delete_Symbols.xlsm启用宏的工作簿批量排序与清理标的列表删除类宏操作前先备份工作簿
Excel_Stock/Excel_Stock_VBA_Macros/Stock_Index_Links.xlsm 与 Stock_Button_Website.xlsm启用宏的工作簿生成索引链接与打开外部站点涉及外部链接,注意公司网络策略
Excel_Stock/Excel_Stock_VBA_Macros/Stock_Highlight_Every_Other_Row.xlsx、Stock_VLOOKUP.xlsx、Stock_Companies_LOOKUP.xlsx普通工作簿格式与查表类辅助不需要宏,可安全打开
Excel_Stock/Bullock_Gold_Mining_Case/VBA_Script.txt 与 Payback_Function.txt纯文本源码把宏代码以文本形式留存,便于阅读代码本身这是唯一能「直接读源码」的地方,属于投资回收期课程案例
Excel 侧的均线公式怎么写:常见做法是用 AVERAGE 配合位移区间(例如对 B 列的第 20 行到第 39 行求平均),再单列一条「短线上穿长线」的判断列,取值只写 0/1。这样做的最大好处是每个中间值都能点开看,排查口径问题比代码快;代价是要换标的或换区间时得手工重排数据区,而且宏一旦改动,历史结果就不可复现了。以仓库里工作簿的实际公式为准。
Matlab

Matlab 这一路有多薄:全目录只有 4 个代码文件

官方 README 把 Matlab 与其它五个工具并列展示,容易让人以为体量相当。按固定提交清点,Matlab_Stock/ 一共 6 个文件,其中代码文件只有 4 个。

文件类型大致内容放到均线策略里能做什么本站状态
DailyReturn.m脚本日收益计算可作为信号收益化的前置步骤未实测(本机无授权)
DailyReturn.mlx实时脚本与上一个文件同题,带可交互输出对照脚本版与实时脚本版的差异未实测
DailyStock.mlx实时脚本日行情获取与处理Matlab 侧的取数写法参考未实测
financial_analysis.mlx实时脚本金融分析示例最接近「一条完整分析流程」的那一份未实测
MATLAB.PNG 与 README.md图片 + 说明目录封面与目录级说明说明里只有描述、软件下载链接与免责声明,无运行步骤可直接读(文本与图片)
结论要说得直白:在 Stock_Analysis_For_Quant 里做「四语言同题对照」,Matlab 那一路只能提供方向性的参考——它给出的是取数与日收益的写法,不是完整的均线策略实现。若你没有 Matlab 授权,不建议为这几个文件单独采购;用 Python 或 R 侧的文件就能完成同一件事,Matlab 侧的差异主要体现在语法与运行时环境上。相关步骤本站未实测,以官方文件与你的实际环境为准。
Alignment

四份结果对不上时,按这张表逐项排查

把四个实现放在一起,结果几乎不可能完全相等。下表的顺序是按「排查成本从低到高」排的,建议从上往下查。

检查项怎么查不一致时先改哪一边允许的偏差范围
样本区间是否相同比对两端第一行与最后一行的日期把四份实现都改成同一段起止日期必须完全一致,否则后续对比无意义
交易日历是否相同数一下行数:同一区间内行数应当接近统一用交易所日历,剔除多余的自然日行数差异应能解释为节假日处理差异
价格字段是否相同看用的是收盘价、复权收盘价还是典型价统一到一个字段,并记录下来必须一致
均线类型与参数确认都是 SMA(20) 与 SMA(60),不是 EMA改参数或改类型,不要两处同时改必须一致
滚动窗口的空值处理看前 19 行是空值还是被填成了数值把空值保留为缺失,不要提前填必须一致,否则会伪造早期信号
信号与成交的时点确认是 T 日收盘成交还是 T+1 成交统一成 T+1,更接近真实可执行性必须一致
成本与滑点是否计入看收益序列里有没有按换手扣减先都不计成本做一次对齐,再统一加成本分两步做,便于归因
数值精度与舍入比对同一天的均线值差异是否在小数点后几位保留足够精度,不要中途四舍五入小幅差异属正常,量级异常才需回查
  1. 先对齐数据,不碰策略

    四个实现读同一份价格文件(可从仓库的样例数据或自己导出的 CSV 开始),只做「读入 + 打印首尾日期」。预期输出:四个实现的起止日期与行数完全一致。这一步不过,后面所有对比都是无效的。

  2. 再对齐单条均线

    只算 SMA(20) 这一列,导出到同一个对照文件。预期输出:同一交易日的均线值在四个实现里量级一致;若差异出现在开头几行,问题在空值处理。

  3. 然后对齐信号状态

    把信号写成 0/1 状态列,而不是买卖点。预期输出:持仓天数接近;若差异很大,多半是「价格穿越均线」与「双均线交叉」两种定义混用了。

  4. 最后才加成本

    在已有换手次数的基础上套统一费率与滑点。预期输出:收益曲线整体下移,但四个实现的相对形态保持一致;若形态变了,说明成本被重复扣减。

  5. 把口径写进结果文件

    文件名带上标的、区间、参数与成本假设,例如包含 SMA20_60 与日期区间。预期输出:半年后你还能凭文件名判断这份结果是怎么算出来的——这正是这个仓库缺的那一环。

Choose

按你的条件选一条路:五种情况对应的实现方式

四条路没有优劣,只有合不合适。下表按「你手上有什么」来给答案。

你的情况建议走哪条理由注意点
不会编程,但有 ExcelExcel 公式路线零环境成本,中间值可肉眼追溯,适合把「均线是什么」弄懂换标的与区间需手工重排;涉及 7 个 .xlsm 时注意宏安全
会一点 PythonPython 路线Stock_Analysis_For_Quant 的指标区有 213 个文件可对照,粒度最细仓库不给依赖清单,先按 notebook 的 import 反推再装
会用 RR 路线技术分析区 159 个脚本多为纯代码,代码短、跑得快,适合改参数做批量对比R 侧默认参数与 Python 库不同,跨语言对比前先统一口径
有 Matlab 授权Matlab 路线 + 一个脚本语言做对照Matlab 侧只有 4 个代码文件,单独用它无法完成完整对照本站未实测;以官方文件与你本机版本为准
只想先看结果、不想装环境先走免部署的技能路线取数与出图可以一次性完成,用来验证你对口径的理解是否正确技能侧产出静态结果,做工程化批量对比仍需脚本语言
要交付可复核的研究Python 或 R 路线,并附口径记录代码可原样重跑,配合上面第二张口径表即可复现务必锁 commit 与记录依赖版本,仓库本身不提供版本信息

先跑通再优化

不管走哪条路,第一次都只做「取数→一条均线→一个 0/1 信号→两个统计数」这四步。跑通之后再叠加第二条均线、成本与参数扫描。反过来的顺序——先写完整策略再排错——通常会把时间都花在环境问题上。

别跳过对齐

四份实现里有两份结果不一致,最常见的根因不是代码错误,而是价格字段或成交时点不同。先把口径表填完,再去比数字,能省掉大量「以为是 bug」的排查。

成本必须算进去

均线策略换手相对频繁,成本对结果的影响会被放大。哪怕只是给换手次数乘上一个固定的单边费率,也比完全不计成本更接近真实;费率请以交易所、券商与你使用的数据源为准。

结果要能说明来源

Stock_Analysis_For_Quant 没有版本发布,复现只能锁 commit。建议把 commit、依赖版本、数据日期写进结果文件名或同目录的说明文件,这样半年后回看仍然能解释这条曲线怎么来的。

FAQ

关于均线策略四实现的常见问题

以下关于 Stock_Analysis_For_Quant 各目录的结论,基于固定提交 df4bd3c58d71 的文件清单与官方 README;本站未运行过仓库中的任何文件,具体实现请以仓库代码与你本机环境为准。

为什么本站只给骨架,不直接给仓库里的 notebook 原文?

因为直接搬运原文既不能说明口径,也不适合作为你自己的研究记录。Stock_Analysis_For_Quant 里的实现分散在不同语言与不同目录,逐份抄写反而会掩盖「同一件事四种写法」的对照价值。骨架的作用是把八项口径显式写出来,你拿它去对照仓库里的实现,才能判断差异出在哪里。仓库文件本身仍是最权威的参照,以其当前状态为准。

四种实现的结果应该完全一致吗?

不应该期待完全一致。即使口径全部对齐,不同语言在浮点精度、缺失值处理、默认年化方式上仍有细微差别;再加上数据源在不同工具里的复权处理可能不同,出现小幅差异是正常的。真正需要警惕的是量级差异,例如持仓天数差一倍——那通常意味着信号定义或数据字段被换掉了,按本页的对齐检查表从上往下查即可。

Matlab 那一份为什么这么薄?

这是仓库的实际情况:按固定提交清点,Matlab_Stock/ 一共 6 个文件,代码文件只有 DailyReturn.m、DailyReturn.mlx、DailyStock.mlx 与 financial_analysis.mlx。官方 README 把六个工具并列展示,但没有说明各目录的体量差异。所以在本仓库里做四语言对照时,Matlab 一路更适合当参考样本,而不是完整实现。以官方文件清单为准。

Excel 里能不能做出和代码一样的均线信号?

可以。做法是给每个交易日写一条「短均线是否大于长均线」的判断列,取值只保留 0 或 1,交易发生点再看该列的相邻变化。这样算出来的信号与代码侧可以逐日对照。代价是换标的后要重排数据区,而且用宏做的部分一旦修改就无法复现历史结果。仓库里的 Excel_Stock_VBA_Macros/ 提供了 7 个启用宏的工作簿作为参考,打开时需启用宏。以工作簿实际公式为准。

去哪找现成的均线实现来对照?

Python 侧看 Python_Stock/Technical_Indicators/ 下的 Moving_Averages.ipynb、SMA.ipynb、Golden_Death_Cross.ipynb,以及两份库总表 1_Technical_Indicators_talib.ipynb 与 1_Technical_Indicators_ta.ipynb;R 侧看 R_Stock/R_Technical_Analysis/R_Moving_Average.R 与相邻的 R_EMA.R;Excel 侧看 Stock_Plot_MA.xlsx。注意 talib 与 ta 两套库的同名指标算法可能有差异,混用会得到不同数值。以仓库当前文件与你安装的库版本为准。

要不要考虑做空与仓位管理?

先把多头单标的、固定仓位跑通,再考虑其它。做空会引入借券成本与可融券标的限制,仓位管理会引入再平衡规则,两者都会让四份实现之间的对齐难度明显上升。建议在口径表里先把「空仓」定义为第三种状态(既不是持有也不是卖空),等对齐完成后再各自扩展。本站不提供任何具体仓位建议,也不涉及实盘执行。

为什么强调把口径写进文件名?

因为这个仓库没有版本发布、没有依赖清单,也没有统一的实验记录格式。同一个目录里存在大量 _Part2、_2 结尾的文件,光看名字无法判断哪个更新、用了什么参数。自己做的每一次实现都带上标的、区间、参数与成本假设,是最省事的可复现手段。这是本站的实践建议,不是官方要求。

下一步:把骨架真的跑起来

上面两段骨架涉及取数与依赖安装,而这个仓库不提供依赖清单——所以第一件事是把自己的环境补齐,并记录下 Python 或 R 的版本。环境与最小运行页给出了按目录反推依赖的三步法、本机的实际探测输出,以及六类真实报错的排查表。