SPL 量化工作台使用教程
前言 —— 量化投资,你也可以
一提起量化投资,普通股民脑海里就会泛起困难的编程语言、繁杂的高频交易、高额的资金门槛,自然会觉得和自己无关。
SPL 量化工作台是北京润乾公司基于开源 SPL 技术实现的一套量化策略设计和回测平台。它让你轻松迈入量化投资的世界——无需编程基础,有 Excel 技能就可以设计策略;无需复杂设备,打开网页就能使用;更无需巨额资金,策略信号人工执行即可。
SPL 量化工作台专为普通投资者设计,具有三大特点:
零编程门槛
告别 Python、C++ 等复杂语言,只需有 Excel 技能就能构建策略。系统将您的公式自动转化为可执行的量化策略,让您专注于投资逻辑而非代码实现。一站式数据服务
每日自动更新 A 股全市场数据,内置近百个常用技术指标(如 MACD、RSI、布林带等),封装复杂的数学运算,您只需 "拿来即用",省去数据收集和处理的烦恼。日 K 线离线策略
专注于基于日 K 线的中低频策略设计,工作台生成信号,再由人工操作,既避免了高昂的自动化交易系统接入成本,又规避了高频交易的技术门槛和资金压力。
在这个工作台上,量化策略的创建和验证变得前所未有的简单:
实时回测:策略修改后立即看到历史表现
可视化分析:清晰直观的收益曲线和风险指标
策略优化:快速调整参数寻找更优组合
现在,量化投资不再是专业人员和机构的专属。无论您是:
想系统验证自己投资理念的散户
希望将经验转化为稳定策略的老股民
对量化感兴趣但缺乏技术背景的投资者
这个工作台都能帮助您以最低的成本,体验专业量化投资的魅力。
量化投资,你也可以!立即访问我们的工作台,开启您的智能投资新时代。
工作台(临时)网址:http://stock.raqsoft.com.cn:8092/model.jsp
因股票信息量大,请在大屏幕电脑上使用浏览器操作,不合适小屏幕手机体验。
工作台首页:https://www.raqsoft.com.cn/wx/splqt.html (长期有效,临时网址变更时可从这里获取最新的)。
社区网址:https://c.raqsoft.com.cn/tag/QuantitativeTrading
有疑问可到社区发贴(微信扫码注册),特别是有需要的新指标或做不出来的策略,都可以提出来,我们会再继续完善补充。
1. 数据和画图
打开网页,在左上角股票代码框中输入股票代码,比如输入‘600690’查看海尔智家,下方即可显示出海尔智家的日 K 线数据。日 K 线数据的列可以在左边进行勾选,只显示需要用到的列。

在这里可以切换复权类型。需要强调的是:这里的复权计算是按起止日期开始计算,而不是从股票上市日和今天开始计算的。比如现在看到的数据是从 2024-09-05 到 2025-09-05 期间的,选择前复权时,最末尾日期,即 2025-09-05 将用不复权价,前面的价格会做复权。反之 ,后复权则是起头日期,即 2024-09-05 用不复权价,后面的价格做复权。这里我们选择前复权,这样的好处是让显示出来价格最接近实际交易价,当然对于策略设计是没有影响的。

在开始和结束输入框中选择起止日期,可以对数据的区间进行过滤,后续的指标计算、策略回测、统计图表的生成都基于这个时间区间进行。

右边提前读数和显示选项,现在不必理会,后续讲到策略时会解释。

还可以用图形的方式观察数据,在左轴、右轴下拉框中选择统计图的 Y 轴,然后用画图,即可显示成图形来查看。


左轴和右轴也可以分别选择多列,这样会生成多条线型图,方便对照:


2. 最简单的固定价策略
我们来尝试做一个固定价格买卖策略,策略内容是这样的:如果当日股票的最低价低于 23 元,就买入;反之如果股票的最高价高于 25 元,就全部卖出。然后循环进行这个步骤,看下能否赚钱。
这里我们假设,每次的买入价格为都为 23 元,卖出价格都为 25 元,每次买入数量为 1 手(100 股)。
首先定义买入价格列,第一步:在添加指标下拉框中选择SPL 公式,然后输出列类型选择价格,输出列名选择买价,表达式里输入23,最后点提交。

此时可以看到数据显示框中多出了买价这列:

同时在买入价格下拉框中也多出了买价选项,选择买价作为买入价格:

接着定义卖出价格列,第一步先重新点选一下添加指标下拉框,重新选择SPL 公式(特别强调:即使当前已经是 SPL 公式了,也需要下拉点选一下,表示新建指标,否则会修改原指标),重新点选后会发现页面刷新了:

此时再选择输出列类型为价格,输出列名为卖价,表达式为25.5,点提交:

最后在卖出价格下拉框中选择卖价作为卖出价格:

买入股数和买入金额是互斥的,是指一次买入交易的股数或金额。A 股市场以“手”为单位(1 手 =100 股),买入时通常需为 100 股或其整数倍(如 100 股、200 股等)。科创板(688 开头)和创业板(300 开头)最低 200 股起,可按 1 股递增。
我们这里以 600690 为例,买入股数填100,最大持仓数为空,表示只要满足买入价格就会持续买入,最后点提交:

这时候会弹出对话框:

点确定即可,因为固定价格买卖不需要买卖信号列,直接满足价格即可买卖。最后界面左侧数据显示框会出现交易明细,右侧的回测结果显示统计值,回测结果旁边显示回测时间:

持仓 / 买入 / 卖出这三列显示的数字,表示当前持仓 / 买入 / 卖出的笔数,每一笔的股数和金额取决于前面定义的买入股数 / 买入金额。
鼠标放到持仓 / 买入 / 卖出的数字上,会显示当前持仓或交易明细,其中股数是指这一笔交易的买入股数,买日 / 卖日是指这一笔交易的买入日期 / 卖出日期,如果这一笔股票买入后在回测区间里一直没有卖出,则卖日会显示为空。买价 / 卖价表示这笔股票的买入价格 / 卖出价格,同样的,如果没有卖掉,卖价也显示为空。买额 = 股数 * 买价 + 手续费,卖额 = 股数 * 卖价 - 手续费,这里的意思其实是,买额相当于进行这一笔交易需要花费的总金额,卖额相当于进行这一笔交易后能获得的现金额。
此时点击下一交易行 / 上一交易行按钮,数据会自动滚动到下一个 / 上一个有交易的行,并高亮显示。

这里可以看到,持仓明细里显示的卖日 / 卖价 / 卖额为空,表示当前买入的股票在回测区间没有卖掉。
界面右侧的回测结果用到了一些指标,解释如下:
占用资金:在给定时间段内完成所有交易需要投入的现金综合(包括手续费)。比如某个策略一周内的买卖资金如下表。不难算出,要完成这些交易,需要投入 800 元,那么该策略的占用资金就是 800 元。
买入资金 |
500 |
卖出资金 |
700 |
买入资金 |
1000 |
卖出资金 |
900 |
现金收益:指买卖股票所获得的价差收益,只计算已卖出的股票。例如,8 块买入,买入 100 股,买入手续费 5 元;15 元卖出,卖出手续费 5 元,那么现金收益就是 15*100-5-8*100-5=690。
持仓价值:当前持有的股票价值。例如持有 A 股票 100 股,当前股价 10 元,那么 A 股票的持仓价值就是 1000。
持仓收益:当前的持仓价值 - 持仓成本。
收益率:指收益总额与投资额的比例。收益总额包括现金收益和持仓收益。投资额就是该股票的占用资金。
买盘数:指希望购买的订单数。
赢利数:策略在给定时间段内交易次数中盈利的次数。
亏损数:策略在给定时间段内交易次数中亏损的次数。
买入资金:给定时间段内策略的总买入资金。
卖出资金:给定时间段内策略的总买入资金。
比如某个策略一周内的买卖资金如下表,那么一周内该策略的买入资金就是 1500 元,卖出资金是 1600 元。
买入资金 |
500 |
卖出资金 |
700 |
买入资金 |
1000 |
卖出资金 |
900 |
日波动率:指策略收益率在一定时间内的变动幅度,它反映了市场的不确定性和风险。波动率越高,收益率的波动越剧烈,资产收益率的不确定性就越强;波动率越低,收益率的波动越平缓,资产收益率的确定性就越强。波动率等于每日收益率的标准差。
最大回撤率:描述策略在回测期可能出现的最大亏损幅度,反映了策略的风险承受能力。最大回撤率越小,说明策略的稳定性越高,风险越低。最大回撤率等于最高收益率与之后最低收益的差值与最高收益率 +1 的比值。
年化收益率:(收益率 +1)^(251/ 交易天数)-1。其中“^”是幂指数符号,251 是假定每年交易天数是固定的 251,有时也用 252,交易天数是策略开始到结束的间隔交易天数。
年化波动率:日波动率 *(251/ 交易天数的平方根)。
夏普率:(年化收益率 - 无风险年化收益率 )/ 年化波动率,用来衡量策略的收益风险比。
手续费的算法不同券商可能会不同,这里采用如下公式计算:
买入手续费 =max( 交易金额 *交易佣金,最低佣金)+ 交易金额 *过户费
卖出手续费 =max( 买入金额 *交易佣金,最低佣金)+ 买入金额 *(过户费+印花税)
其中,交易佣金、最低佣金、过户费、印花税在设置里配置:


前面定义策略时,把最大持仓数置空,表示回测时只要信号列返回 1,第二天就执行买入操作;如果设为数字 n,则只要当前持仓笔数等于 n,即使信号列返回 1,第二天也不会操作。我们可以把上面的策略按最大持仓数为空和为 1 做个对比:


从上面两图可以看出,如果最大持仓数为空,则只要满足买入条件,就会持续买入;反之,只要当前持仓数等于最大持仓数,即使满足买入条件,也不会再次买入。
l SPL公式:常数
SPL 公式中可以直接引用常数,用法和 excel 一致
3. 隔日振幅突破策略
这个策略的核心思想是:利用昨日巨大的振幅和价格变动,来预测未来一天到几天的短期趋势,并在第二天开盘附近买入,在后续的日子里卖出。
A. 策略逻辑
前一天出现异常大的振幅,通常意味着市场出现了激烈的多空博弈。如果股价最终收在高位(形成一根坚挺的阳线),可能预示着多方获胜,上涨势头有望延续。我们策略就是在信号出现后,第二天跟进,并持有一定时间。
B. 买入信号条件
l 今日振幅巨大:(今日最高价 - 今日最低价 ) / 昨日收盘价 > 阈值 A
公式解释:今日的振幅超过了正常水平。阈值 A是一个可调参数,例如可以设为5%(0.05)。这意味着振幅要大于 5% 才算异常。
l 收阳线且涨幅可观:(今日收盘价 - 今日开盘价 ) / 今日开盘价 > 阈值 B
公式解释:虽然是巨大振幅,但最终是多方力量更强,收出了一根实体阳线。阈值 B可以设为2%(0.02)或3%(0.03)。
C. 买入时机:
在信号日出现的第二天(T+1 日),以昨日收盘价买入。
D. 卖出时机:
买入后,设置一个目标盈利点和止损点。
止盈:当股价从买入价上涨达到 X% 时,卖出。例如 X = 5%。
止损:当股价从买入价下跌达到 Y% 时,坚决卖出止损。例如 Y = 3%。
补充条件:如果一直没达到止盈或止损,则在买入后的第 M 天(例如第 5 天)无条件卖出。
根据上述描述,我们来实现此策略:
第一步定义买入信号列:
买卖信号列的输出规则是这样:1 表示第二天执行买入;-1 表示第二天执行卖出;0 表示不操作。需要再次说明的是,这里设计的离线策略,也就是用截止昨日的收盘数据算出的买卖信号列值,来决定第二天的买卖操作。
指标类型选SPL 公式,输出列名填买入信号,输出列类型选信号,表达式为if((最高 - 最低)/ 收盘 [-1]>0.05 && (收盘 - 开盘)/ 开盘 >0.02,1,0),点提交

l SPL公式:列名引用
SPL 公式中可以直接引用数据窗口中显示的列名:

比如上例中的开盘、收盘、最高、最低就是数据显示窗口中的列名。
l SPL公式:四则运算符
说明:SPL 的四则运算符大体和 excel 一致,少量会有不同,这里列出 excel 和 SPL 的异同:
相同之处
1) 基本运算符相同:+-*/ > >= < <=
2) 运算优先级相同:乘除法优先于加减法,可用()改变顺序
不同之处
特性 |
Excel |
SPL公式 |
幂运算 |
^ |
power(),如 power(2,3) |
取模运算 |
MOD() |
% (如 5%2 返回 1) |
布尔值 |
TRUE/FALSE |
true/false(小写 ) |
比较运算 |
<> |
!= |
空值 |
用 NA() 或空单元格或 NULL |
null(小写 ) |
大小写 |
大小写不敏感 |
大小写敏感,大部分函数和关键词小写,少数大写 |
逻辑运算符与 |
AND() |
&& (如收盘 >=5 && 收盘 <=10) |
或 |
OR() |
|| (如收盘 <=5 || 收盘 >=10) |
非 |
NOT() |
! (如买卖信号列!=0) |
l SPL公式:什么是收盘 [-1]?
收盘 [-1]表示引用当前行的前一行中的收盘列值;相应地,收盘 [1]表示引用当前行的后一行中的收盘列值。这是 SPL 语言中特有的相对位置引用语法,常用于需要访问相邻行数据的计算场景。
基本特性:
· 相对定位:基于当前行的相对位置访问
· 动态计算:引用的具体值取决于当前处理的行位置
· 边界处理:当引用超出序列范围时 (如第一行的前一行,或最后一行的后一行),返回 null
典型应用场景
· 计算涨幅
· 查找相邻行
· 实现滑动窗口计算
图示说明
· 示例数据表
日期 |
收盘 |
2022-01-04 |
29.15 |
2022-01-05 |
29.09 |
2022-01-06 |
29.26 |
2022-01-07 |
29.48 |
· 收盘 [-1] 和收盘 [1] 运算过程
当前处理行 |
收盘[-1]取值 |
收盘[1]取值 |
收盘[-1]计算逻辑 |
收盘[1]计算逻辑 |
2022-01-04 |
null(无前一行 ) |
29.09 |
[无前一行 ] |
取 2022-01-05收盘值 |
2022-01-05 |
29.15 |
29.26 |
取 2022-01-05 收盘值 |
取 2022-01-06 收盘值 |
2022-01-06 |
29.09 |
29.48 |
取 2022-01-05收盘值 |
取 2022-01-07收盘值 |
2022-01-07 |
29.26 |
null(无后一行) |
取 2022-01-06 收盘值 |
[无后一行] |
边界情况处理
· 首行:收盘[-1] 返回 null
· 尾行:收盘[1] 返回 null
· 跨组分引用:在分组计算中,相对引用不会跨组
· 多行偏移:也支持如收盘 [-2] (前两行)、收盘[3](后三行) 等写法
这种相对位置引用机制使得时间序列计算、滑动窗口分析等场景的表达式非常简洁直观。
l SPL公式:if() 函数
函数说明:
条件判断函数,根据条件表达式的真假,返回不同分支的计算结果
函数语法:
if(a) 当条件 a 为真时,返回 true,否则返回 false
if(a,b,c) 当条件 a 为真时,返回 b 的计算结果,否则返回 c 的计算结果
if(x1:y1,…,xk:yk;y) 当条件 x1 为真时,返回 y1 的计算结果;否则当条件 x2 为真时返回 y2 的计算结果;否则……依此类推,如果所有 xk 均为假,则返回 y 的计算结果。
用法示例:
l if((收盘 - 开盘)/ 开盘 >0.02)
表达式含义:当(收盘 - 开盘)/ 开盘 >0.02满足时返回true,否则返回false
l if((最高 - 最低)/ 收盘 [-1]>0.05 && (收盘 - 开盘)/ 开盘 >0.02,1,0)
表达式含义:当(最高 - 最低)/ 收盘 [-1]>0.05 && (收盘 - 开盘)/ 开盘 >0.02满足时返回1,否则返回0
l if(收盘 <23:1, 收盘 >28:-1;0)
表达式的含义:当收盘 <23满足时返回1,当收盘 >28满足时返回-1,否则返回0
第二步定义策略:买入信号列选买入信号,买入价格选昨日收盘价,卖出信号列和卖出价格不选(意思是不按此操作),止盈填5,止损填3,最长持仓日填5,平仓缺省价格选昨日收盘价,最后提交:


提交后,可看到回测结果如下:

可以看出,当涨幅超过 5% 或跌幅超过 3% 时,会自动卖出。
4. 双均线策略——SPL 公式
我们再来用这个工作台实现业界常见的双均线策略。
双均线策略基于这样一种假设:观察长期均线(如 10 日均线), 和短期均线(如 5 日均线)。股票价格的动量会朝着短期均线的方向移动。当短期均线穿过长期均线,并超过长期移动平均线时,动量将向上,此时股价可能会上涨,判断为买入。反之,如果短期均线的移动方向相反,股价则可能下跌,判断为卖出。
这时候,对于回测时间区间的第一天来说,判断是否买入卖出要用前面 10 个交易日的数据来计算,因此需要往前读 10 天的数,这就用到了提前读数的功能:

提前读的这 10 天数据可以显示也可以不显示,由显示勾选框来决定。
此策略用到的长期均线和短期均线都需要先定义成指标,方便后面的表达式使用,所以我们第一步先定义这两个指标:
选择SPL 公式,输出列类型为普通,输出列名为MA5(表示为 5 日均线),表达式为收盘 [-4:0].avg():

这句代码中出现了中括号的语法,[a:b]的形式表示取区间值,如,收盘 [-4:0]表示取区间收盘价,从往前数第 4 天开始取,一直取到当前行(0 表示当前行),即共计取到 5 天的收盘价,再用avg()函数求平均值就是 5 日 MA;同理,收盘 [-9:0].avg()就是计算 10 日均价,10 日均价的输出列名定义为 MA10:

l SPL公式:什么是收盘 [-4:0]
在 SPL 公式中,收盘 [-4:0]表示对收盘列进行相对位置范围引用,这是一种强大的滑动窗口引用语法。
收盘 [-4:0]表示以当前行为中心,向前取 4 行,再加上当前行本身(0 表示当前行)构成的子序列。这种引用方式特别适合实现滑动窗口计算、移动平均等需要上下文数据的分析场景。"
· 基本特性
o 窗口定义:[起始偏移: 结束偏移] 定义相对位置窗口
o 包含边界:包含起始和结束偏移位置的行
o 动态窗口:窗口大小固定但内容随当前行位置变化
o 自动截断:当窗口超出序列边界时自动截断
· 示例数据表
行号 |
日期 |
收盘 |
1 |
2022-01-04 |
28.85 |
2 |
2022-01-05 |
29.43 |
3 |
2022-01-06 |
29.57 |
4 |
2022-01-07 |
30.22 |
5 |
2022-01-10 |
29.62 |
· 收盘 [-4:0]运算过程
当前处理行 |
收盘 [-4:0] 取值 |
窗口包含的行位置 |
2022-01-04 |
[28.85] |
行 1,无法向前取 4 行 |
2022-01-05 |
[28.85,29.43] |
行 1-2,无法向前取足 4 行 |
2022-01-06 |
[28.85,29.43,29.57] |
行 1-3,无法向前取足 4 行 |
2022-01-07 |
[28.85,29.43,29.57,30.22] |
行 1-4,无法向前取足 4 行 |
2022-01-10 |
[28.85,29.43,29.57,30.22,29.62] |
行 1-5,完整取足前 4 行 |
· 边界情况处理
o 起始边界:当向前取不到足够行时,窗口自动缩小
o 结束边界:当向后取不到足够行时,窗口自动缩小
o 空窗口:极端情况下可能返回空序列
o 对称窗口:也支持如收盘 [-2:2] 这样的对称窗口
· 应用场景
这种灵活的窗口引用机制使得 SPL 公式能够用非常简洁的语法实现复杂的滑动窗口分析,包括:
o 移动平均计算
o 滚动统计量
o 前后行对比分析
o 局部趋势计算等
l SPL公式:avg() 函数
函数说明:
用于计算序列中所有数值元素的算术平均值,它会自动忽略非数值元素,确保计算的准确性。
函数语法:
A.avg()
参数说明:
A 序列
用法示例:
收盘 [-4:0].avg()
类似的函数:
count:统计序列中非空元素的数量
sum:计算数值序列中所有元素的总和,自动忽略非数值元素
max:找出序列中的最大值
min:找出序列中的最小值
mode:找出序列中出现频率最高的值(众数)
以上这些函数的语法和用法都和 avg 一致,不再一一赘述。
有了这两个均价指标列,可以先以图形的方式观察一下:


从图上可以看到一些很明显的上穿下穿交叉点。
下一步就定义买卖信号列:
选择SPL 公式,输出列类型选择信号,输出列名 MA5_10_Signal,表达式 if(MA5>MA10 && MA5[-1]<=MA10[-1]:1,MA5<MA10 && MA5[-1]>=MA10[-1]:-1;0),最后点提交:

数据显示框中可以看到 MA5_10_Signal 的值:

说明:if(MA5>MA10 && MA5[-1]<=MA10[-1]:1,MA5<MA10 && MA5[-1]>=MA10[-1]:-1;0)表达式的含义:当MA5>MA10 && MA5[-1]<=MA10[-1]满足时返回1,当MA5<MA10 && MA5[-1]>=MA10[-1]满足时返回-1,否则返回0,类似于 Excel 中的表达式:ifs(MA5>MA10 && MA5[-1]<=MA10[-1],1,MA5<MA10 && MA5[-1]>=MA10[-1],-1,0)
有了信号列,我们再用统计图来对比看一下 MA5,MA10, MA5_10_Signal,这里就用到右轴了:


可以看出 MA5_10_Signal 取值为 1 或 -1 的日期,正好是 MA5 和 MA10 交叉后的第一天。
第二步定义策略:买入 / 卖出信号列均下拉选择MA5_10_Signal,买入卖出价格均选择昨日收盘价(因为根据昨日的买卖信号列的值决定第二天的买卖操作,在开盘前只知道昨日的收盘价,没法知道第二天的价格,所以用昨日的收盘价来回测更加符合实际情况),买入股数填 100,最大持仓数置空(表示持续买入),最后点提交:

这里,也可以把买入价格和卖出价格配置为今日开盘 / 收盘价,来感觉一下策略的效果,毕竟实际操盘时是人工操作,可以灵活选用第二天当时发生的实际价格。
5. 双均线策略——使用内置指标
从头写拼出这些指标还是有些麻烦,特别是那个信号列的公式并不简单。其实这个工作台中已经内置了一些常用的指标,可以直接使用,不用写这些复杂的公式了,比如双均线策略,我们可以用内置指标来定义 MA5 和 MA10:
第一步:添加指标下拉框中选择 MA- 移动平均线:

第二步:数据列选择收盘,周期填5,MA 输出列名填MA5:

提交后数据显示框中就出现了 MA5 列,可以看到,其值和前面通过 SPL 公式定义的 MA5 的值是一样的。同样的方法,我们把 MA10 也定义了,其它选项都和 MA5 一致,就是周期改成 10,输出列名改成 MA10 即可。
再选择GDX- 金叉死叉信号,短线选MA5,长线选MA10,输出列名填GDX5_10:

提交后可以看到,GDX5_10的返回值和MA5_10_Signal的返回值完全一致:

第二步:定义策略,此时买卖信号列选择GDX5_10, 买卖价格选择昨日收盘价,买入股数填100,最大持仓数置空,可以看到回测结果和 SPL 公式定义出来的完全一致:


如果对 MA5 和 MA10 两个均线值不关心,还可以一步到位,使用单个内置指标来完成此策略的定义:
添加指标下拉框中选择MAGDX- 双均线金叉死叉信号:
定义指标:

提交后,可以看到 MAGDX 和前面两种方式定义的指标值完全一样:

6. MACD 背离策略
MACD(Moving Average Convergence and Divergence)是 Geral Appel 于 1979 年提出的,利用收盘价的短期(常用为 12 日)指数移动平均线(EMA)与长期(常用为 26 日)指数移动平均线 (EMA) 之间的聚合与分离状况,对买进、卖出时机作出研判的技术指标。
MACD 从均线指标 EMA 衍化而来,对把握趋势性行情有着很好的应用效果,它的顶底背离是一种经过检验的“抄底逃顶”方法,是不少中长期投资者在实战中都会考虑的指标。
MACD 计算方法:
短线 EMA:短线的指数移动平均,移动窗口通常取 12;
EMA=q* 当前价格 +(1-q)* EMA[-1]
其中 q 是平滑系数,q=2/(移动周期 +1)。
后续的 EMA 都是这样计算,只是移动周期取值不同。
长线 EMA:长线的指数移动平均,移动窗口通常取 26;
离差平均值 DEA:DIFF 的指数移动平均,移动窗口通常取 9;
MACD:2 *(DIFF - DEA)
下面介绍 MACD 背离买卖策略:
金叉:DIFF 上穿 DEA
死叉:DIFF 下穿 DEA
底背离:股价创新低但 DIFF 没有新低。把最近一次死叉到金叉的区间称为区间 1,把再前一次死叉到金叉的区间称为区间 2。区间 1 的最低股价小于区间 2 的最低股价,区间 1 的最低 DIFF 大于区间 2 的最低 DIFF,此时的金叉作为买入信号。
如下图箭头处,股票价格创新低,dif 指标背离式走高,出现底背离

顶背离:股价创新高但 DIFF 没有新高。把最近一次金叉到死叉的区间称为区间 3,把再前一次金叉到死叉的区间称为区间 4。区间 3 的最高股价大于区间 4 的最高股价,区间 3 的最高 DIFF 小于区间 4 的最高 DIFF,此时的死叉作为卖出信号。
如下图箭头处,股票价格还在创新高,但 dif 指标背离式走低,出现顶背离。

基于上述的算法,我们使用内置指标分三步实现:
第一步:添加指标下拉框选择 MACD- 异同移动平均线:

此内置指标一次性返回三列。
第二步下拉选择GDX- 金死叉信号:

GDX 的定义用到了第一步算出来的 DIF 和 DEA
第三步下拉选择DVG- 顶底背离信号:

有了上述指标,我们来定义策略,此时涉及到提前读多少天数据的问题,根据上述算法,为了正确计算第一天的信号值,需要确保 MACD 指标的初始值稳定。MACD(默认参数 12,26,9)的计算涉及以下步骤:
EMA12 和 EMA26:需要足够的历史数据使指数移动平均线(EMA)收敛。通常需要:
EMA12:至少 12*3=36 个交易日(3 倍周期)
EMA26:至少 26*3=78 个交易日
DEA(信号线):MACD 的 9 日 EMA(即 DEA)需要额外 9*3=27 个交易日的数据稳定。
顶底背离检测:为了识别价格与 MACD 的背离,通常需要至少一个完整的波动周期(例如 1-3 个月),因此建议额外提供 60 个交易日以上的数据。
建议:
最低要求:回测开始前至少提供110个交易日的历史数据(覆盖 78+27 个交易日,并留有余量)。
理想情况:提供200个交易日以上的数据,确保 EMA 充分收敛,且能捕捉到前期的价格波动趋势。
原因:
若数据不足,初期 EMA 计算不准确,可能导致 MACD/DIF 值失真,进而产生虚假背离信号。
顶底背离是相对历史高低点的比较,足够的历史数据能避免边界误差。
这里我们选择提前读 200 天的数据,按如下方式定义策略:

提交后可以发现,如果回测区间是 2022 年,则全年没有买入,如果回测区间是 2023 年,则有两笔买卖,年收益率达到 6.09%,说明此策略还不错,能躲开熊市:

MACD 顶底背离策略也有单个的内置指标,如果对 DIF/DEA 等指标不关心的话,也可以用单个指标直接算出:
下拉选择MACDSIG-MACD 顶底背离信号,数据列和中长短周期均用缺省值,DVG 输出列填MACDSIG:

提交后,在买卖信号列下拉框中选择MACDSIG,买入股数填100,最大持仓数置空,买卖价格选择昨日收盘价:

7. 平仓
平仓是指投资者通过反向交易(如卖出已持有的多头头寸或买入回补空头头寸)将现有持仓了结的行为,其目的是终止当前头寸的市场风险暴露,实现盈利或止损。平仓是交易流程中的关键环节,其触发条件可基于价格信号、时间周期、风险控制或策略规则等,直接影响策略的盈亏结果和资金利用率。在回测中,平仓逻辑需与实际交易场景一致,并考虑滑点、手续费等摩擦成本。
这里提供了两种平仓方式:
固定比例止盈止损
适用场景:趋势跟踪或波段交易策略。
逻辑:当收益或亏损达到预设阈值时平仓(如盈利 10% 止盈,亏损 5% 止损)。
作用:锁定利润、控制单笔损失。
固定持有期
适用场景:统计套利或均值回归策略。
逻辑:持仓 N 天后强制平仓(如配对交易中 5 天后平仓)。
作用:避免长期暴露风险,匹配策略假设的时间框架。
我们以 601985 这支股票为例做如下配置:

可以看到,当达到止盈止损阈值或最长持仓日时,股票就会被强制卖出,如果不配置平仓选项,结果如下:

此时会发现因为一直不满足卖出条件,所以股票一直处于持仓中。
这里还提供了一个选项:多次买入分别平仓,其含义是针对止盈幅度、止损幅度、最长持仓日三个属性,如果此项勾选,则每笔交易独立核算,如果不勾选,则价格按所有持仓的均价,最长持仓日按最后一笔买入日期计算。
我们可以做个简单的对比,就用刚才的配置,分别把多次买入分别平仓打勾和不打勾:


可以看出,如果分别平仓,则单笔计算是否符合平仓条件,单笔卖出;如果不分别平仓,则会按照持仓股票统一计算均价和最后一笔交易的最长持仓日,再判断是否平仓,一旦满足,全部清仓。
平仓时的卖出价格可以在设置里配置:


一般选择昨日收盘价,也可以自己通过指标计算出来。
8. 指数比较
策略的好坏可以通过将回测结果和指数做一个对比,看看表现如何,这里可以使用指数比较功能。当前策略提交后,在界面右下角选择上证 50 指数:

然后点击指数比较按钮:

即可在新窗口看到当前策略和选定指数的直观图形对比:

从图上可以看出,使用 MACD 顶底背离策略,在 2023 年可以跑赢上证 50 指数。图上还能看到一个 beta 值,它是一种风险指数,用来衡量个别股票或股票基金相对于整个股市的价格波动情况,在这里它表达的是当前策略的收益和你所选的指数的波动对比,这个值小于 1,表示当前策略的收益比所选指数的波动小。
没有回测的时候,也可以直接点指数比较,查看当前股票的收盘价和指数的对比:

从图上可以看出,beta 大于 1,说明该股票的收盘价波动是比指数大的,但是使用当前策略的收益波动却比所选指数小,说明这个策略比较稳健。
9. 多票模式以及结果查看
还可以同时回测多只股票:

在弹出框中先根据基本面选股:

假设我们认为最近人工智能比较看好,尤其看好其中的算法开发方面,因此选择上证主板,申万一级为计算机,申万二级为软件开发,点击筛选按钮后,选出了 15 只符合条件的股票代码,点击开始回测按钮后,可以在数据显示框里同时看到每只股票的回测结果:

此时,右边的回测结果是这几只股票的合计值。需要注意的是,这里的占用资金并不是简单的相加,而是整个回测时间区间里曾经被占用的最大资金数。
数据显示窗口上的列标题,可以点击后排序,然后点击右上方的导出按钮,把当前数据导出成 csv 文件,然后再挨个查看,挑选合适的去回测单票的效果。
想看单票的回测结果,只需要在股票代码的下拉框里选择对应的股票:

这时候,中间的数据且就会显示出单票时的买卖记录和持仓情况。

如果想回到前面的多只股票回测结果显示界面,点左下角的多票结果按钮:

如果想看多票回测过程中的每一笔交易,则点左下角的交易汇总:

此时可以看到多票回测过程中的每一笔交易明细和持仓情况:

再点各票效益,即可切换回原来的界面。
10. 股票池调整
根据基本面选股后,实际参与回测的股票可以不用股票池中的所有股,从股票池中选出某种指标较适合的股,来参与回测,调整周期可以是每天、每周、每月、每年的某个月等等。
比如,从股票池中选出过去五个交易日平均涨幅最高的五只股票参与回测,可以这么做:
第一步:定义涨幅指标

第二步:定义前五日的日均涨幅

第三步:定义按每周调整股票池,选出前五日均涨幅最高的 5 只股票参与回测

点击【开始回测】:

可以看到,23 年通过每周选 5 日均涨幅排名前 5 的股票参与回测,最后有买入操作的股票一共四只。
需要说明的是,这里的选出前 n 只股票,会把并列的情况考虑进去,凡是并列的,不管几个都会被选出,因此可以灵活利用这个功能,实现条件判断选出。
举例来说,想选出前三个交易日连涨的股票,可以这么定义指标:

表达式if(日涨幅 [-2:0].select(~>0).len()==3, 1, 0)的含义是:如果前三个交易日的日涨幅均大于 0,则返回 1,否则返回 0,因此股票池调整可以这么定义:

由于此表达式只会返回 1 或者 0,因此按降序排序后,只需要选出前 1 名的,就会把所有返回 1 的股票选出来了,这样间接实现了按条件判断选股。
还可以利用财务指标对股票池进行调整,举例来说,每年的 5 月选出市值最小的前 5 个进行回测,可以这样操作:
第一步添加指标里输入市值两个字,进行动态筛选,然后下拉框里选择总市值:

提交后,在股票池里按总市值正序排序,选出前 5 只股票进行回测:

11. 仓位控制
量化交易中,仓位管理是平衡风险与收益的关键。如果仓位过重,一旦市场走势不利,可能遭受巨大损失。而仓位过轻,又可能错过盈利机会。合适的仓位能在风险和收益间找到平衡,使收益稳定增长。不同的市场环境对仓位管理要求不同。在牛市时,适当增加仓位可以获取更多收益。但在熊市或者震荡市时,就需要降低仓位来规避风险。
我们主要采用两种仓位管理方法:
固定金额法:在这种方法中,每次交易投入固定金额的资金。这种方法简单易行,但可能不够灵活,无法根据市场情况和交易者的风险承受能力进行调整。
固定比例法:每次交易投入账户总资金的固定百分比。这种方法使得随着账户价值的增长或减少,交易仓位大小也会相应调整。
在多票回测弹出窗口中勾选是否需要仓位控制,输入总资金数,每次买入比例或者每次买入金额:

点击开始回测后,数据显示区域会显示这几只股票的买入卖出情况:

点左下角的【交易汇总】,可以看到每一笔实际的买入卖出数据:

现金最小值指的是回测过程中,帐户剩余资金少于现金最小值时,会自动补足,不填表示不做这个补足动作;
现金最大值指的是回测过程中,帐户剩余资金大于现金最大值时,多出部分会自动被抽走不再参与交易以保护已经获得的赢利。不填表示不做这个处理,即所有帐户上的资金都会继续参与交易。
此举用于保证回测过程中的资金总数始终保持在一定的范围内。可以尝试用此配置对比一下:

把股票池调整取消,让更多股票参与回测去占用资金,这样才能看出区别,首先是不配置现金最大值最小值的回测结果:

可以看到 11 月份的时候资金占用最多的时候达到 87 万,然后配置现金最小值为 30 万,最大值为 110 万:

可以看到 11 月份资金最多占用了 95 万,说明在资金低于 30 万的时候,回测脚本自动给补足了资金。
12. 信号输出与实操
在实操时如何用策略来指导下单?这里所讲的策略都是离线策略,适用于低频交易。在离线策略中,可由系统计算出下单信号,然后人工操作下单买卖。这样我们只需在系统中根据策略计算出当天是否有下单信号就可以了,此时可以使用信号输出的功能:

弹出窗口中选择昨天或今天的日期,然后点击计算:

可以看到界面上列出了该日期下信号为 1 或 -1 的股票,根据此输出可以很方便地进行今天或第二天的操作。
对于卖出信号,可以只输出当前持仓股票的卖出信号,比如:

如果当前持仓股票不填,则输出所有参与回测的股票卖出信号。
13. 波动性突破策略
这个策略的基本逻辑是:当市场的波动性(即价格区间)突然放大时,往往预示着新趋势的开始。我们用一个简单的指标来量化这种波动,并据此进行交易。
A. 指标公式
这个策略只使用一个指标,我们称之为波动率因子 (Volatility Factor, VF)。
VF = ln(最高价 / 最低价) * 10
最高价:当前 K 线的最高价。
最低价:当前 K 线的最低价。
ln:自然对数。ln(最高价 / 最低价) 本质上是计算当日价格的变化幅度(对数收益率的一种形式)。乘以 10 是为了放大这个值,使其更容易被观察到和用于触发信号。
这个值的含义:VF 值越大,代表当天的价格波动范围(从最高到最低)越大。
B. 买入和卖出时机
这个策略需要一个波动性基准。我们假设如果当前的波动性超过了过去一段时间的平均水平,就可能发生“突破”。
策略规则(以做多为例):
计算基准波动率 (Benchmark Volatility):
计算过去 N 天(例如 N=20)的 VF 值的简单移动平均(SMA)。我们称之为 VF_MA。
VF_MA = SMA(VF, 20)
买入信号 (开仓信号):
如果 当前 K 线的 VF>VF_MA* 系数 K(例如 K=1.5)
并且 当前 K 线是阳线(收盘价 > 开盘价)
则在 下一根 K 线开盘时 买入。
逻辑:波动性显著放大(超过平均水平的 1.5 倍)且价格收涨,表明可能开始了向上的突破行情。
卖出信号 (平仓信号):
买入后,设置一个目标盈利点和止损点。
o 止盈:当股价从买入价上涨达到 X% 时,卖出。例如 X = 5%。
o 止损:当股价从买入价下跌达到 Y% 时,坚决卖出止损。例如 Y = 3%。
o 补充条件:如果一直没达到止盈或止损,则在买入后的第 M 天(例如第 5 天)无条件卖出。
根据上述描述,我们来实现此策略:
第一步先定义波动率因子指标:
选择SPL 公式,输出列名填VF,输出列类型选普通,表达式为ln(最高 / 最低)*10:

l SPL公式:ln() 函数
函数说明:
计算一个数值的自然对数(以常数 e 为底的对数)。
函数语法:
ln(number)
参数说明:
number 数值类型
用法示例:
ln(100) // 输出结果4.605170185988091
第二步定义买入信号列:
选择SPL 公式,输出列名填VF_signal,输出列类型选信号,表达式为if(VF>VF[-20:-1].avg()*1.5 && 收盘 > 开盘,1,0)

第三步定义策略:买入信号列选VF_signal,买入价格选昨日收盘价,卖出信号列和卖出价格均不设(其意思是不按此操作),止盈幅度填5,止损幅度填3,最长持仓日填5,平仓缺省价格选昨日收盘价:


提交后可看到回测结果:

可以看出使用该策略,600690 这只股票在 2022 年实现了盈利。
14. 中位数通道突破策略
该策略的核心思想是:将中位数作为价格的“均衡线”或“价值中枢”,当价格显著偏离这个中枢时,就会产生回归的倾向。我们利用这个特性来寻找买卖点。
A. 策略逻辑简述
· 中位数 (中线): 代表了最近 N 期内市场的平均成本中心,比简单移动平均线 (SMA) 更能抵抗极端值的干扰。
· 通道的宽度: 代表了最近 N 期市场的波动幅度。市场波动大,通道就宽,需要更大的力度才能突破;市场波动小,通道就窄,轻微的波动就可能触发信号。
· 突破: 价格突破通道,意味着打破了之前的平衡状态,有可能开启一波新的趋势。
B. 策略公式
计算中位数线 (Median Line):
中线 = 最近 N 个收盘价的中位数
参数 N: 回顾的周期,例如 20 天(可根据不同市场调整)。
计算上下通道线 (Channel Bands):
上轨 = 中线 + (N 周期内的最高价 - N 周期内的最低价) * K
下轨 = 中线 - (N 周期内的最高价 - N 周期内的最低价) * K
参数 K: 通道宽度的系数,例如 0.5。K 值越大,通道越宽,交易信号越少;K 值越小,通道越窄,交易信号越多。
C. 买入和卖出时机
买入信号:
当收盘价向上突破上轨时,视为价格进入强势上涨趋势,产生买入信号。卖出信号:
当收盘价向下跌破下轨时,视为价格进入强势下跌趋势,产生卖出信号。
根据上述描述,我们来实现此策略:
第一步先按顺序定义如下指标:
过去 20 日收盘价中位数:

l SPL公式:median() 函数
函数说明:
计算一个数值序列的中位数,中位数比简单平均更能抵抗极端值。
函数语法:
参数说明:
将序列A根据其长度平均分成n段,返回第k段与第k+1段的分界值,有参数x时,先对A计算表达式x,然后再分段。
k省略n不省略时,将各段的分界值组成序列返回。
k、n参数全省略时,如果序列长度是奇数返回中间位置的成员值;如果序列长度是偶数返回中间两个成员的平均值。对于不能平均分段的序列采取逻辑分段。
用法示例:
[1,2,3,4,5,6,7,8,9,10].median() // 返回 5.5
[1,2,3,4,5,6,7,8,9,10].median(1:2) // 返回 5.5
[1,2,3,4,5,6,7,8,9,10].median(1:3) // 返回 4
=[1,2,3,4,5,6,7,8,9,10].median(1:3,~*~) // 返回 16
过去 20 日最高价:

过去 20 日最低价:

中位数通道上轨:

中位数通道下轨:

第二步定义买卖信号列:

第三步定义策略:

点提交后,可以看到回测结果:

600690 这只股票,使用中位数通道突破策略,在 2024 年实现了 7.64% 的盈利。
15. 放量高点阻力突破策略
核心思想:市场在放量大涨时形成的阶段性高点具有重要的阻力意义。当价格后续能够强势突破这个由多个放量高点构成的“阻力墙”时,往往意味着真正的强势趋势到来,是极佳的入场时机。
A、策略逻辑
识别关键放量点:首先,我们不是关注所有的高点,而是只关注那些伴随着成交量显著放大(能量驱动)的价格高点。这些点代表了当时多空双方激烈博弈的位置,尤其是多方获胜的位置,其高点将成为未来重要的阻力位。
构建阻力区域:单个放量高点的阻力可能不可靠。因此,我们找出近期多个这样的放量高点,并取它们中的最高价 TOP 5 的平均值,形成一个“阻力区域”。这个区域比单一价格点更具代表性,过滤了噪音。
等待有效突破:当价格运行到这个阻力区域附近时,我们并不立即行动。而是等待价格以强势的姿态(例如,用收盘价确认)完全突破这个区域,这表明买方力量已经完全消化了历史上所有的抛压,后市继续上涨的概率较大。
出场与风险控制:入场后,如果价格再次跌回阻力区域下方,说明此次突破是“假突破”,应立即止损离场。
B、计算公式与参数
N:回顾的历史周期,例如 N=100(天)。
Volume_Multiple:成交量放大倍数,例如 2。
Top_X:所要选取的放量高点的个数,例如 X=5。
Lookback_Close:突破确认的周期,例如 2(天),用于判断收盘价是否站稳。
具体计算步骤:
筛选条件 K 线:
对于每一个交易日 t,在过去的 N 根 K 线中,筛选出所有满足以下条件的 K 线:
条件: (成交量 (t_i) / 成交量 (t_i-1)) >= Volume_Multiple
找出顶级高点:
将所有满足条件的 K 线对应的最高价 (high(t_i)) 取出,形成一个列表。
从这个列表中,找出前 Top_X 个最大的最高价(即 Top 5 Highest Highs)。
计算关键阻力位:
阻力位 Resistance = 平均值 (Top_X 个最高价)
生成交易信号:
买入信号(Bullish Breakout):
当前收盘价 (close(t)) > Resistance
AND
前 M 根 K 线的收盘价(例如 close(t-1)) <= Resistance(确保是刚刚突破,而不是早已突破)卖出信号(Sell / Stop Loss):
当前收盘价 (close(t)) < Resistance(突破后再次跌回阻力位下方,视为假突破,止损出场)
C、买卖时机
买入时机(开多仓):
在交易日结束时(例如,下午 3 点),如果系统计算出当日收盘价首次成功突破了计算得到的 Resistance 阻力位,则在下一个交易日开盘时以昨日收盘价买入。
为什么收盘价确认?避免盘中假突破的噪音。
为什么下一个交易日开盘买入?这是一个非常普遍且合理的交易指令执行方式,确保了策略的可操作性。
卖出时机(平多仓 / 止损):
主动止损:在持仓后的任何一天,如果收盘价跌破了之前突破的那个 Resistance 位
(此时它已转变为支撑位),则在下一个交易日开盘时卖出平仓,止损离场。
主动止盈:可以设置一个固定的风险回报比,例如“盈利达到止损幅度 2 倍时止盈离
场”。
假设你在 Entry_Price 入场,止损价是 Resistance。
止损幅度 Stop_Loss_Range = Entry_Price - Resistance
目标盈利价 Take_Profit_Price = Entry_Price + (2 * Stop_Loss_Range)
当收盘价达到或超过 Take_Profit_Price 时,下一个交易日开盘止盈。
被动止盈:如果一直未触发止损和主动止盈,可以一直持有,直到反向信号出现(例
如,一个基于放量低点的支撑下破策略信号)。
根据上述描述,我们来实现此策略(需要注意,这里因为需要用到前 100 个交易日的数据,所以要先设置提前读 100 天的数据):
第一步先定义关键阻力位 Resistance 指标:

l SPL公式:什么是~?
SPL 公式中,波浪号~用作当前行引用符号。当对 K 线数据进行循环计算时,~表示当前正在处理的那根 K 线。在循环函数(如sum()、select()等)中,~提供了对当前行的直接引用,简化了集合运算的表达。
用法示例:
~[-100:-1] // 其含义为过去 100 个交易日的 K 线数据组成的集合
技术特性说明:
上下文绑定:~的取值由当前执行的迭代上下文决定
动态引用:在多层嵌套迭代中,~总是指向最内层循环的当前元素
类型多态:~可以表示简单数据类型的值,也可以表示行、序列等对象
表达式简写:与字段名配合使用时可以省略,如~. 成交量可简写为成交量。之前例子都使用了这个简写形式,也就一直没有出现过 ~。
此符号的设计显著提升了 SPL 公式处理结构化数据时的简洁性和表达效率。
l SPL公式:什么是select 函数?
函数说明:
选出序列中符合条件的成员
语法:
A.select(x) |
备注:
针对序列 A 的每个成员计算表达式 x,返回使表达式的值为真的成员组成的新序列。参数省略时返回所有成员。
参数:
A |
序列。 |
x |
布尔表达式,可为 null。 |
返回值:
序列 / 序表
用法示例:
~[-100:-1].select(成交量 / 成交量 [-1]>=2) // 其含义为从过去 100 个交易日的 K 线数据中,选出成交量比头天翻倍的 K 线
l SPL公式:什么是top 函数?
函数说明:
序列成员计算表达式后获取前 n 个值组成的序列。
语法:
A.top(n,x) |
针对序列 A 的成员计算表达式 x 后排序,返回前 n 个 x 值组成的序列。 |
A.top(n;x,...) |
针对序列 A 的成员计算表达式 x,…后排序,返回前 n 个 A 成员组成的序列。 |
A.top(n,y,x) |
针对序列 A 的成员先计算表达式 x,再对 x 结果值进行 y 计算,然后根据 y 值对 x 排序,获取前 n 个 x 值组成的序列。 |
备注:
针对序列的每个成员计算表达式,排序后返回前 n 个值组成的序列。
序列存在重复成员时,默认采用连续排名方式。
n>0 时取前 n 个最小值,n<0 时取前 n 个最大值,n 为 0 时返回 null,n 不可省略,x 省略解释为 ~。
参数:
A |
序列。 |
n |
整数。 |
y |
表达式。 |
x |
表达式。 |
选项:
@1 |
n为±1 时返回单值。 |
@0 |
不忽略 null,缺省忽略 null。 |
@r |
采用美式排序,即并列名次占用名次。 |
@i |
采用中式排序,即并列名次不占用名次。 |
序列
用法示例:
~[-100:-1].select(成交量 / 成交量 [-1]>=2).top(-5, 最高) // 其含义为从过去 100 个交易日的 K 线数中,选出成交量比头天翻倍的 K 线,再从中选出最高价排前五的 K 线
第二步:定义买入信号:

第三步:定义卖出信号:

第四步:定义策略:

提交后可以看到回测结果:

可以看到,600690 这只股票使用此策略后,在 23 年实现了 3.08% 的盈利。
16. 布林带均值回归策略
策略逻辑
核心思想:我们认为股价就像一根橡皮筋,拉得越开(偏离越远),反弹(回归)的力量就越强。
工具:我们使用一个由三条线组成的通道——布林带(Bollinger Bands)。
中轨:是股价过去一段时间的简单移动平均线(SMA),代表平均成本。
上轨:中轨加上 N 倍的标准差。代表“偏离过远”的上限。
下轨:中轨减去 N 倍的标准差。代表“偏离过远”的下限。
操作:当股价触及或突破下轨,说明价格被“超卖”,可能过低,是买入信号。当股价触及或突破上轨,说明价格被“超买”,可能过高,是卖出信号。
计算公式
你需要为每个交易日计算三个值:
中轨 (Middle Band):MID = SMA(Close, N)
计算过去 N 个交易日收盘价的简单移动平均线。
N 是时间窗口,常用 20 天。
标准差 (Standard Deviation):STD = Standard Deviation(Close, N)
计算过去 N 个交易日收盘价的标准差。
上轨 (Upper Band):UP = MID + K * STD
下轨 (Lower Band):LOW = MID - K * STD
K 是标准差的倍数,常用 2。这意味着上轨和下轨分别位于中轨上方和下方 2 个标准差的位置。
根据统计学,在正态分布中,价格落在均值±2 倍标准差范围内的概率约为 95%。因此,突破这个范围被认为是小概率事件,意味着趋势可能即将反转。
常用参数:N = 20,K = 2
买入与卖出时机
买入时机 (开多仓 / 做多):
信号:当股票的收盘价从下方触及或跌破布林带下轨 (LOW)时,生成买入信号。
逻辑理解:价格已经跌到了“ statistically 非常便宜”的区域,市场情绪过度悲观,预期价格会反弹回升至中轨甚至更高。
卖出时机 (平多仓 / 止盈):
信号:当股票的收盘价从上方触及或突破布林带上轨 (UP)时,可以视为卖出(或甚至做空)信号。
逻辑理解:价格已经回到了平均成本线,均值回归的目标达到。或者,价格涨到了“ statistically 非常昂贵”的区域,市场情绪过度狂热,预期价格会下跌回调。
止损:
任何策略都必须有止损。例如,可以在买入价下方设置一个固定百分比(如 -5%)作为止损点,如果价格继续下跌跌破该点,则坚决卖出,承认错误。
根据上述描述,我们来实现此策略(需要注意,这里因为需要用到前 20 个交易日的数据,所以要先设置提前读 20 天的数据):
第一步先按顺序定义如下指标:


l SPL公式:什么是var@sr 函数?
函数说明:
计算向量 (序列) 的总体方差。
语法:
var(V)
备注:
计算向量V的总体方差。
选项:
@s |
计算向量的样本方差,除以n-1。 |
@r |
计算V的总体方差后再开方。 |
参数:
V |
向量。V是空集或 null 时返回 null。 |
返回值:
数值型
用法示例:
var@sr(收盘 [-20:-1]) // 其含义为计算过去 20 个交易日的收盘价标准差


第二步定义买卖信号列:

第三步定义策略:

第四步使用多票回测:

筛选出 15 只股票参与回测,点击开始回测,可以看到如下回测结果:

可以看出,使用此策略,这 15 只股票在 21 年的收益率达到 7.43%
17. 海龟策略
海龟策略(Turtle Strategy)是一种经典的投资和交易策略。
它的内容是这样的:在股价超过过去 N 个交易日的股价最高点时买入,在股价低于过去 N 个交易日的股价最低点时卖出(N 通常设为 20)。上述的若干个最高点和最低点会组成一个通道,称为“唐奇安通道 (Donchian Channel)”。原始的唐奇安通道有两条线,过去 N 天最高价的最大值形成的线叫做上阻力线,过去 N 天最低价的最小值形成线叫做下支撑线。

唐奇安通道的主要作用是帮助交易者确定买入和卖出时机。因为唐奇安通道是根据最高价和最低价计算出来的,通道的宽窄又随着价格的变化自动调整,所以大多数时候价格是在通道之内运行,很少突破其上下轨道的。
也就是说,价格并不会随意突破阻力线和支撑线,但如果有效突破,那就预示着大行情可能将会出现。此时交易者可以根据支撑和阻力线,确定买进或卖出的具体时机。比如:当价格向上突破阻力线就买入,当价格跌破支撑线就卖出。
我们把突破“唐奇安通道”上阻力线时设为买入信号(1),低于下支撑线时设为卖出信号(-1),其他时间为不操作(0)。
根据上述原理,我们来实现这个策略:
首先,使用 "002466"(天齐锂业)股票在 21 年的数据,由于海龟策略需要计算 20 日最高价和最低价,需要用到前 20 交易日的数据,所以还要设置提前读 20 天的数据:

然后,在添加指标中选择 SPL 公式:
输出列类型为普通,输出列名为 don_up(上轨线),表达式为最高 [-20:-1].max()

输出列类型为普通,输出列名为 don_down(下轨线),表达式为最低 [-20:-1].min()

这个中括号 [-20:-1] 表示从当前行往前数 20 个交易日到昨日,共 20 天的最高价 / 最低价。
用统计图来观察唐奇安通道,左轴选择 don_up,don_down, 收盘,点画图按钮:

图上可以看到大约从 4 月到 8 月,有一波明显的上涨行情,且在 4 月底部的时候收盘价有突破上阻力线。
再来生成买卖信号,选择SPL 公式,输出列类型选择信号,输出列名DC,表达式if(收盘 >don_up:1, 收盘 <don_down:-1; 0):

点提交后,数据显示框中可以看到 DC 的值:

这个表达式的意思是:
当收盘价突破上轨时买入 (1)
当收盘价跌破下轨时卖出 (-1)
其他情况不操作 (0)
用画图功能把价格通道和信号指标放在一起看:

从图上看,抓住箭头处的买入时机,可以赚一波大行情。
现在可以回测了,设置回测参数:
买卖信号列选择 DC
买卖价格用 "昨日收盘价"(更符合实际)
每次买 100 股
最大持仓数 1

提交后立即看到回测结果:

整个执行时间仅 1 秒左右。这个回测结果还能和上证指数做对比,选择沪深 300,点击指标比较按钮,即可看到如下对比图:

可以看到天齐锂业使用海龟策略,在 2021 年跑赢了沪深 300指数。
还可以进一步的优化这个策略:
参数优化:可以尝试不同的通道周期(如 15 日或 30 日)
// 15日通道版本
don_up: 最高 [-15:-1].max()
don_down: 最低 [-15:-1].min()
增加过滤条件:可以结合波动率或成交量过滤假突破
// 增加波动率条件
if(收盘 > don_up && var@rs( 收盘 [-20:-1])>0.02:1, 收盘 <don_down && var@rs(收盘 [-20:-1])>0.02:-1; 0)
3. 增加仓位管理:可以分 3-4 次加仓,降低风险,这里可以用最大持仓数 + 买入股数的配置

假设总资金够买 400 股的,那么如果买入股数配置为 400,最大持仓数配置为 1,就表示一次性买入;如果买入股数配置为 100,最大持仓数配置为 4,则表示分四次加仓。
18. 趋势交易策略
趋势就是市场运动的方向,在通常的情况下,市场不会朝某一个方向直来直去,市场运动的特征表现为震荡前行,酷似一系列前赴后继的波浪,具有明显的峰和谷。所谓趋势就是这些波峰和波谷依次上升或下降的方向。股价在上涨或下跌时通常会形成趋势,如果能抓住这些趋势,会带来不错的收益,本章就介绍一种常见的趋势交易策略。
在介绍策略之前先定义两个名词:
l 最近的波谷:股价低于之前和之后 M (缺省 3) 天的股价。
l 波谷前的波峰:最近的波谷之前股价高于之前和之后 M 天的股价。
买入策略为:
l 最近的波谷低于最近 N(缺省 252) 天股价的 5 分位(5 分位是指将数据从小到大排序,然后五等分,取第 1 个分界值),且
l 当天的股价高于波谷前的波峰。
同时满足上述两个条件,则下单买入,如下图:

卖出策略:
l 股价低于最近的波谷,或
l 收益率超过 R (缺省 10%)。
满足上述两个条件中的任何一个,就全部卖出。

根据上述策略描述,我们按以下步骤实现策略定义(提前读 252 天的数据):
第一步添加指标中选择趋势交易指标,做如下定义:

第二步:定义策略

根据策略描述,当盈利率达到 R 时卖出,所以我们在止盈幅度里配置 10%,提交后可看到如下回测结果:

使用此策略,600990 这只股票在最近一年的回测中盈利达到 16.48%
19. KNN 简单策略
机器学习算法是近年量化策略的热点,我们在这一章中通过一个简单的例子感受一下。
KNN 是机器学习中的一种算法,它的核心思想是:如果一个样本在特征空间中的 K 个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别。更通俗点说,KNN 可以找到和目标样本最相似的 K 个样本,然后根据其中的大多数来预测目标样本。
我们也可以用这种方法来预测股票的涨跌,构造一个特征空间然后在历史数据中找到和当日特征最相似的 K 个交易日数据,然后根据这 K 个交易日第二天的涨跌情况来预测第二天的涨跌(大多数涨就预测为涨,大多数跌就预测为跌)。
KNN 简单策略的具体方法如下:
l 将第二天是否上涨作为预测目标,即计算收盘 [1]- 收盘,大于 0 时目标值为 1,小于 0 时为 -1,其余为 0。
l 增加两个特征,最高价 - 最低价和收盘价 - 开盘价作为特征空间
l 计算历史数据和当日样本特征之间的距离,距离越近越相似。具体为:计算当天样本特征和之前 n 个交易日的特征距离,找到距离最近的 m 个交易日数据,把这 m 个交易日目标值的众数作为第二天的预测结果。
根据上述策略描述,我们按以下步骤实现策略定义(提前读 100 天的数据):
第一步添加指标中选择 KNN 指标,做如下定义:

此指标返回的是根据 KNN 算法预测第二天的收盘价后判断是否买卖,返回值直接是 1,-1,0,因此可以直接作为信号列使用。
第二步定义买卖策略:

提交后,可看到回测结果:

601606 这只股票,在最近一年使用此策略回测中,获得 253.57% 的盈利。
20. 线性回归预测策略
基于线性代数的回归分析也是量化策略中常用到的数学工具,我们来尝试一下,并了解其中的一些注意事项。
在股市投资中,投资者往往需要根据历史数据来预测未来的市场趋势,以便做出更明智的投资决策。线性回归作为一种经典的统计工具,在股票量化策略中发挥着举足轻重的作用,它通过对历史数据进行统计分析,建立出一个尽可能反映市场规律的模型,从而预测未来的股票价格走势。
线性回归的基本原理是找出一个最适合的直线(这条直线也称为模型),使这条直线能够最好地拟合给定的数据点。这条直线通常被称为“回归线”,它的公式如下:
y = a + bx
其中,y 是因变量(股票价格),x 是自变量(如历史价格、历史财务指标等),a 和 b 是待求解的参数。
例如,我们可以选取公司的市盈率、市净率、营业收入增长率等财务指标作为自变量,股票价格作为因变量,建立线性回归模型。通过对大量历史数据的拟合,可以得到这些财务指标与股票价格之间的线性关系方程。在未来,当我们知道了这些财务指标的值时,就可以通过这个方程来预测股票价格的大致范围。
再例如,通过对过去一段时间内股票价格的变化进行线性回归分析,可以得到价格变化的趋势线。如果趋势线向上倾斜,说明股票价格处于上升趋势;如果趋势线向下倾斜,说明股票价格处于下降趋势。
需要注意的是线性回归算法提供了一种预测股票价格的方法,但并不能保证 100% 的准确性。因此,在使用线性回归模型时,需要结合其他信息和个人判断,制定出更全面的投资策略。此外,还需要定期对模型进行验证和调整,以适应市场的变化。
根据上述策略描述,我们按以下步骤实现策略定义(提前读 105 天的数据):
第一步添加指标中选择 KNN 指标,做如下定义:

此指标返回的是根据线性回归模型预测的第二天的收盘价。
第二步定义买卖信号列,其规则为当预测第二天收盘价格上涨,则买入,下跌则卖出。为了避免误差导致的无谓买入卖出,即价格基本持平仅仅因为尾数有少量误差,因此我们规定上涨达 0.5% 才买入,下跌超 0.5% 才卖出:

第三步定义策略:

提交后,可以看到如下回测结果:

600562 这只股票,在最近一年中使用线性回归预测策略,获得了 4.95% 的收益率。
附录 1 界面元素速查
股票代码: 整数,如 1 表示 sz.000001, 600000 表示 sh.600000。
复权:前复权:保持新时间点的价格不变,对历史时间点的价格进行调整,使得股价连续。后复权:保持早期时间点价格不变,调整后续时间点的价格。
开始:需要回测的起始时间。
结束:需要回测的结束时间。
提前读数:买卖触发时机以及买卖价格,是由头几天或者更早的数据计算而来,而不同的策略需要用到的历史数据的区间不同,所以由用户自行根据策略的需求设置提前读几天的数。
显示:是否把提前读的数显示出来。
左轴右轴:统计图的Y轴,左右轴均可多选。X轴固定为日期。
保存/打开:将当前设计的策略保存到本地(json 格式),下次可以直接打开使用。
新建:新建一个策略。
分享:将当前策略分享给其他人浏览,此时会产生一个链接,只需要把链接复制下来发给别人,别人即可点击链接查看你的策略。
导出:将当前数据浏览窗口的内容导出到excel文件。
买卖信号列:先定义信号类型的指标列,当指标列返回1时表示买入,-1表示卖出,0表示不操作。特别强调,今天的信号列返回值,用于明天的买入卖出操作。
买入价格/卖出价格:如果头天算出来买卖信号列的值为1或-1,则第二天会用买入价格/卖出价格执行买卖操作。但是,如果第二天的最低价格高于买入价格,或最高价格低于卖出价格,则买卖操作执行失败。因为这里主要做基于日线的离线策略,原则上不能使用未来信息,因此在今日交易中会缺省使用昨日收盘价,也可以改成今日收盘价来感觉策略的效果。
买入股数:一次买入操作时买入的股数。此配置和买入金额互斥。
买入金额:一次买入操作时买入的金额。此配置和买入股数互斥。
最大持仓数:为空表示不限制持仓数量,碰到信号合适就会买入;大于等于1时,若当前持仓小于这个数时,碰到信号合适就会买入,否则将拒绝买入。
止盈幅度:当前盈利百分比达到配置值时,不管卖出信号列返回值多少,都在第二天强制执行卖出操作。
止损幅度:当前损失百分比达到配置值时,不管卖出信号列返回值多少,都在第二天强制执行卖出操作。
最长持仓日:买入后,持续持仓日数达到配置值,不管卖出信号列返回值多少,都在第二天强制执行卖出操作。
多次买入分别平仓:针对止盈幅度、止损幅度、最长持仓日三个属性,如果此项勾选,则每笔独立核算,如果不勾选,则价格按所有持仓的均价,最长持仓日按最后一笔买入日期计算。
设置:
交易佣金:模拟实际交易时产生的佣金,在计算手续费时会用到,手续费会体现在占用资金、收益率等的计算中。手续费的计算公式:
买入手续费 =max( 交易金额 *交易佣金,最低佣金)+ 交易金额 *过户费
卖出手续费 =max( 买入金额 *交易佣金,最低佣金)+ 买入金额 *(过户费+印花税)
最低佣金:同上
过户费:同上
印花税:同上
平仓缺省价格:当使用止盈、止损、最长持仓日平仓时,使用此价格。
年化日数:将策略在回测期间的表现(收益率、波动率)标准化为一年的表现,以便进行跨策略、跨资产的比较。主流选择是252,365两种。
夏普率基数:在计算年化夏普比率时,用于表示年化无风险收益率的基准,参考目前的国债、定期等的收益,一般设置为3左右。
上一交易行/下一交易行:左侧数据的当前选中行自动滚动到 上一个/下一个 有买入卖出交易的行。
信号输出:输出指定日期买卖信号列的返回值。
多票回测:同时对多只股票进行回测操作。

仓位管理:
是否需要仓位管理:此选项不勾时,以下三个参数无效。
总资金数:当占用资金超过此值,不再执行买入。
每次买入比例:单笔买入的金额占总资金数的比例。
每次买入金额:单笔买入的金额。
现金最小值:回测过程中,帐户剩余资金少于现金最小值时,会自动补足。
现金最大值:回测过程中,帐户剩余资金大于现金最大值时,会自动抽走。此举用于保证回测过程中的资金总数始终保持在一定的范围内。
选股条件:
通过市场板块、证监会行业、申万行业、上市日、市值等属性,对股票基本面进行筛选
股票池调整:定期将股票池中的股票按指标进行排序,筛选出前n名进行回测,未被选中的股票不参与回测。调整周期可以是日、周、月等
添加指标:选择指标的类型,除了SPL公式外,还有丰富的内置指标。
SPL公式:
输出列类型:
普通:主要用于二次计算,如定义输出列名为median,表达式为:(最高+最低)/2,其含义为当天价格区间的中位数。
信号:返回1表示触发买入,返回-1表示触发卖出,返回0表示不操作。此处定义完,才会在上面的买卖信号列下拉框中出现。
价格:若按头天的收盘价或者当天的开盘价买卖,则不需要定义,直接在买卖价格下拉框中选择即可,其它情况需要先定义,然后才会出现在买卖价格下拉框里。特别强调,今日下单是用昨日算出的价格。
多票结果:使用多票回测时,若想同时看多票的回测结果,可点此按钮;若想切换到单票的明细,可在左上角的股票代码下拉框里选择某只股票即可。
指数比较:策略的好坏可以通过将回测结果和指数做一个对比,看看表现如何,这就是指数比较功能。
附录 2 常用计算指标
价格趋势类指标
价格摆动类指标
超买超卖指标
压力支撑指标
相对市场指标
成交量指标
量价指标
能量指标
新增指标
K 线形态
其它
附录 3 常用外部指标
一些财务报表、股票所属的行业、指数等数据,做成了外部指标,可以在添加指标里选用。对于季频的财报,当前日 K 线以最新一次发布的数据为准;指数未指明开盘的,均为当日收盘价,否则为当日开盘价。
财务主要指标 |
归属于母公司股东的净利润 |
股本 |
基本每股收益 |
归属于母公司股东的每股净资产 |
总资产 |
总负债 |
营业总收入 |
营业收入 |
营业利润 |
利润总额 |
归母净利润同比比例 |
归属于普通股东的净利润 |
归属于普通股东的净资产 |
财务衍生指标 |
基本每股收益 |
每股净资产 |
每股资本公积 |
每股未分配利润 |
平均净资产收益率 ROE |
营业利润同比增长率 |
净资产同比增长率 |
基本每股收益同比增长率 |
研发费用 |
资产负债率 |
净利润同比增长率 |
基础指标 |
总股本 |
流通股本 |
当日换手率 |
估值指标 |
市盈率 |
最新年报市盈率 |
最新年报市净率 |
市值指标 |
总市值 |
A股流通市值 |
资产负债表 |
应收账款 |
应收票据 |
定期存款 |
流动资产合计 |
非流动资产合计 |
资产总计 |
流动负债合计 |
非流动负债合计 |
负债合计 |
股东权益合计 |
负债和股东权益合计 |
股票 |
证监会行业 |
申万行业一级 |
申万行业二级 |
指数 (无开盘两字的为当日收盘价) |
上证 A 股指数 |
上证 A 股指数开盘 |
上证 50 指数 |
上证 50 指数开盘 |
沪深 300 指数 |
沪深 300 指数开盘 |
创业板综合指数 |
创业板综合指数开盘 |
上证综合指数 |
上证综合指数开盘 |
附录 4 常用 SPL 公式
四则运算符
说明:SPL 的四则运算符大体和 excel 一致,少量会有不同,这里列出 excel 和 SPL 的异同:
相同之处
3) 基本运算符相同:+-*/ > >= < <=
4) 运算优先级相同:乘除法优先于加减法,可用()改变顺序
不同之处
特性 |
Excel |
集算器 SPL |
幂运算 |
^ |
power(),如 power(2,3) |
取模运算 |
MOD() |
% (如 5%2 返回 1) |
布尔值 |
TRUE/FALSE |
true/false(小写 ) |
比较运算 |
<> |
!= |
空值 |
用 NA() 或空单元格或 NULL |
null(小写 ) |
大小写 |
大小写不敏感 |
大小写敏感,大部分函数和关键词小写,少数大写 |
逻辑运算符与 |
AND() |
&& (如收盘 >=5 && 收盘 <=10) |
或 |
OR() |
|| (如收盘 <=5 || 收盘 >=10) |
非 |
NOT() |
! (如买卖信号列!=0) |
行引用
~
SPL 公式中,波浪号~用作当前行引用符号。当对 K 线数据进行循环计算时,~表示当前正在处理的那根 K 线。在循环函数(如sum()、select()等)中,~提供了对当前行的直接引用,简化了集合运算的表达。
用法示例:
~[-100:-1] // 其含义为往前数 100 行的数据组成的集合
技术特性说明:
上下文绑定:~的取值由当前执行的迭代上下文决定
动态引用:在多层嵌套迭代中,~总是指向最内层循环的当前元素
类型多态:~可以表示简单数据类型的值,也可以表示行、序列等对象
表达式简写:与字段名配合使用时可以省略,如~. 成交量可简写为成交量。
此符号的设计显著提升了 SPL 公式处理结构化数据时的简洁性和表达效率。
[n]
[n] 一般配合列名使用,比如收盘 [-1];也可以和 ~ 配合使用,比如 ~[-1],表示前一行。
n 为负数时表示引用当前行的前 n 行中的指定列值;相应地,n 为正数时表示引用当前行的后 n 行中的指定列值;n 为 0 则表示当前行的指定列值。
这是 SPL 公式中特有的相对位置引用语法,常用于需要访问相邻行数据的计算场景。
基本特性:
· 相对定位:基于当前行的相对位置访问
· 动态计算:引用的具体值取决于当前处理的行位置
· 边界处理:当引用超出序列范围时 (如第一行的前一行,或最后一行的后一行),返回 null
典型应用场景
· 计算涨幅
· 查找相邻行
· 实现滑动窗口计算
图示说明
· 示例数据表
日期 |
收盘 |
2022-01-04 |
29.15 |
2022-01-05 |
29.09 |
2022-01-06 |
29.26 |
2022-01-07 |
29.48 |
· 收盘 [-1] 和收盘 [1] 运算过程
当前处理行 |
收盘[-1]取值 |
收盘[1]取值 |
收盘[-1]计算逻辑 |
收盘[1]计算逻辑 |
2022-01-04 |
null(无前一行 ) |
29.09 |
[无前一行 ] |
取 2022-01-05收盘值 |
2022-01-05 |
29.15 |
29.26 |
取 2022-01-05 收盘值 |
取 2022-01-06 收盘值 |
2022-01-06 |
29.09 |
29.48 |
取 2022-01-05收盘值 |
取 2022-01-07收盘值 |
2022-01-07 |
29.26 |
null(无后一行) |
取 2022-01-06 收盘值 |
[无后一行] |
边界情况处理
· 首行:收盘[-1] 返回 null
· 尾行:收盘[1] 返回 null
· 跨组分引用:在分组计算中,相对引用不会跨组
· 多行偏移:也支持如收盘 [-2] (前两行)、收盘[3](后三行) 等写法
这种相对位置引用机制使得时间序列计算、滑动窗口分析等场景的表达式非常简洁直观。
[m:n]
和 [n] 一样,[m:n]也一般配合列名或者~使用,比如收盘 [-4:0]表示往前数 4 行,到当前行,一共五行的收盘列的值组成的集合;~[-4:0]表示往前数 4 行到当前行,一共五行组成的集合。这是一种强大的滑动窗口引用语法。
当 m,n 为负数时,表示以当前行为中心,向前数 m,n 行;当 m,n 为正数时,表示以当前行为中心,向后数 m,n 行;0 则表示当前行。[m:n] 表示从第 m 行到第 n 行构成的序列。这种引用方式特别适合实现滑动窗口计算、移动平均等需要上下文数据的分析场景。"
· 基本特性
o 窗口定义:[起始偏移: 结束偏移] 定义相对位置窗口
o 包含边界:包含起始和结束偏移位置的行
o 动态窗口:窗口大小固定但内容随当前行位置变化
o 自动截断:当窗口超出序列边界时自动截断
· 示例数据表
行号 |
日期 |
收盘 |
1 |
2022-01-04 |
28.85 |
2 |
2022-01-05 |
29.43 |
3 |
2022-01-06 |
29.57 |
4 |
2022-01-07 |
30.22 |
5 |
2022-01-10 |
29.62 |
· 收盘 [-4:0]运算过程
当前处理行 |
收盘 [-4:0] 取值 |
窗口包含的行位置 |
2022-01-04 |
[28.85] |
行 1,无法向前取 4 行 |
2022-01-05 |
[28.85,29.43] |
行 1-2,无法向前取足 4 行 |
2022-01-06 |
[28.85,29.43,29.57] |
行 1-3,无法向前取足 4 行 |
2022-01-07 |
[28.85,29.43,29.57,30.22] |
行 1-4,无法向前取足 4 行 |
2022-01-10 |
[28.85,29.43,29.57,30.22,29.62] |
行 1-5,完整取足前 4 行 |
· 边界情况处理
o 起始边界:当向前取不到足够行时,窗口自动缩小
o 结束边界:当向后取不到足够行时,窗口自动缩小
o 空窗口:极端情况下可能返回空序列
o 对称窗口:也支持如收盘 [-2:2] 这样的对称窗口
· 应用场景
这种灵活的窗口引用机制使得 SPL 公式能够用非常简洁的语法实现复杂的滑动窗口分析,包括:
o 移动平均计算
o 滚动统计量
o 前后行对比分析
o 局部趋势计算等
