动平均线 * ta.hma(source, length) 船体移动平均线HMA * ta.rma(source, length) RSI中使用的移动平均线 * ta.vwap(source) 成交量加权平均 * ta.vwma(source, length) length K线的 source 的成交量加权移动平均值
plot(ta.sma, 'sma')
plot(ta.ema, 'ema')
plot(ta.wma, 'wma')
量化投资起源于上世纪60年代,而下面的每一个指标都曾“各领风骚”过,当然有些指标如今还在使用。如果你看到了某些指标符合你的交易思路,你可以在优宽平台一台代码尝试下。
pine_rsi(x, y) =>
u = math.max(x - x[1], 0) // upward ta.change
d = math.max(x[1] - x, 0) // downward ta.change
rs = ta.rma(u, y) / ta.rma(d, y)
res = 100 - 100 / (1 + rs)
res
if ta.rsi <= 20
strategy.entry("buy", strategy.long, qty=1)
if ta.rsi >= 30
strategy.close_all("buy", comment = "close long")
if ta.rsi >= 80
strategy.entry("short", strategy.short, qty=1)
if ta.rsi <= 70
strategy.close_all("short", comment = "close short")
plot(ta.rsi(close, 7), 'rsi值')
相对强弱指标(RSI)是技术指标中的一种,强弱指标理论认为,任何市价的大涨或者大跌,均在0—100之间波动。 根据常态分析,认为RSI值在30-70之间的变动属正常情况,在80—90时,被认为市场已达超买状态,至此市场价格自然面临回落调整;而在10—20时,被认为市场已达超卖状态,至此市场价格自然面临企稳回升。
期货作为时间序列的数据,当然少不了对它的统计计算。基本的指标,平均数,中位数,方差,百分位数等,内置函数都有包含;初步的统计分析,相关分析,线性回归分析等,pine语言也可以满足。
runtime.log('最⾼值',ta.highest(close, 10) )
runtime.log('最⾼k线',ta.highestbars(close, 10) )
runtime.log('衡量均值差异', ta.dev(close, 10) )
runtime.log('标准差', ta.stdev(close, 10))
runtime.log('⽅差',ta.variance(close, 10))
runtime.log('range',ta.range(close, 10))
runtime.log('众数', ta.mode(close, 10))
runtime.log('中位数', ta.median(close, 10))
runtime.log('总和',ta.cum(close,10))
runtime.log('差分',ta.change(close,10))
runtime.log('百分比排名',ta.percentrank(close,10))
runtime.log(ta.barssince(close>open) )
plot(ta.correlation(close, volume, 14),'相关系数',overlay= false)
plot(ta.linreg(close, 14,0) ,'线性回归预测值',overlay= true)
最后,ta系列内置函数还有一些帮助逻辑判断的函数
设置condition条件为’close>open’,即为阳线,设置返回值为close,出现次数为n:
runtime.log('第一根阳线收盘价', ta.valuewhen(close > open , close, 0))
runtime.log('第二根阳线收盘价', ta.valuewhen(close > open , close, 1))
总体而言,本节课的内容确实比较多,其实大家也不必太过担心记忆这些函数。你可以首先记住大致的概念,而在你对大盘市场观察过程中,如果发现某些交易思路或者交易指标比较适合,你可以重新回想起来这些指标,去使用它,或者在此基础上编写新的量化指标,添加进入你的量化策略,也许下一个量化指标就是由你来命名的。
大家好,今天我们来学习Pine语言array数组的操作。数组作为具有某一长度的元素集合,你可以添加,删除,修改你需要的元素,并进行相关的计算展示工作。尽管内置函数可以帮助我们进行某些数组集合的操作,但是很多时候,内置函数并不能满足我们所有的需要,因此我们需要创建数组进行我们所需要的操作。
在前面的章节,我们学习过数组可由以下两种方式进行创建:
a = array.from(ele1,ele2...)
b = array.new(n,ele)
array.from不限制元素的类型,布尔值,字符型,数字都可以添加;array.from第一个值填写重复的个数,第二个值添加重复的元素(也可以不写,这样创建一个数量为n,元素为null的数组)。Pine语言中还有很多和类型相关的与array.new类似的函数:array.new_int()、array.new_bool()、array.new_color()、array.new_string()等。
数组可以在脚本的全局范围内声明,也可以在函数或if分支的本地范围内声明。var关键字也可以作用与数组的声明模式,使用var关键字声明的数组在每个策略周期执行完成后,会保留在这个策略周期内array的变动,而没有添加关键词var的array在每次策略周期内,都会重新更新一次。
var a = array.from(0)
b = array.from(0)
if bar_index == 1
array.push(a, bar_index)
array.push(b, bar_index)
else if bar_index == 2
array.push(a, bar_index)
array.push(b, bar_index)
else ibar_index == 3
runtime.log("a:", a)
runtime.log("b:", b)
runtime.error("stop")
可以看到a数组的变动都持续确定了下来,没有被重置过。b数组则在每个BAR上都被初始化。最终打印的时候仍然只有一个元素,数值0。
数组的增加操作相关函数:
array.unshift():数组起始位置增加
array.insert():数组设定位置增加
array.push():数组末尾增加
a = array.from(1, 2, 3)
array.unshift(a, "X")
runtime.log("数组a:", a)
a2 = array.from(1, 2, 3)
array.insert(a2, 1, "Y")
runtime.log("数组a2:", a2)
a3 = array.from(1, 2, 3)
array.push(a3, "D")
runtime.log("数组a3:", a3)
runtime.error("stop")
数组的删除操作相关函数:
array.shift():删除数组起始位置
array.remove():删除数组设定位置元素
array.pop():删除数组末尾位置元素
array.clear():删除数组全部元素
a = array.from(1, 2, 3)
array.shift(a)
runtime.log("数组a:", a)
a2 = array.from(1, 2, 3)
array.remove(a2, 1)
runtime.log("数组a2:", a2)
a3 = array.from(1, 2, 3)
array.pop(a3)
runtime.log("数组a3:", a3)
a4 = array.from(1, 2, 3)
array.clear(a4)
runtime.log("数组a4:", a4)
runtime.error("stop")
使用array.get获取数组中指定索引位置的元素,使用array.set修改数组中指定索引位置的元素。
array.get的第一个参数为要处理的数组,第二个参数为指定的索引。
array.set的第一个参数为要处理的数组,第二个参数为指定的索引,第三个参数为要写入的元素。
a = array.from(1,2,3,4,5)
runtime.log('元素1', array.get(a,0))
array.set(a,0,100)
runtime.log('元素1', array.get(a,0))
runtime.error('stop')
通过举例证明,array.get帮助我们获取所需位置的元素,array.set修改所需位置的元素。
使用数组,以及数组的一些增加、删除函数我们可以构造出「队列」数据结构。队列是一种在编程领域经常使用的结构,队列的特点就是:先进先出。这样就可以确保队列中存在的数据都是最新的数据。
移动平均值sma大家都很熟悉,sma以固定周期为窗口,计算窗口内的平均值。使用array数组,我们可以构建sma计算的原始代码:
var a = array.new_float(0)
length = 10
if not barstate.ishistory
array.push(a, close)
if array.size(a) > length
array.shift(a)
sum = 0.0
for [index, ele] in a
sum += ele
avgPrice = array.size(a) == length ? sum / length : na
plot(avgPrice, title="avgPrice")
plot(ta.sma(close, length), title="ta.sma")
通过将10设为固定周期,在策略开始,首先使用push往array里添加元素,直到数组的长度大于10,使用shift删除数组第一个元素,确保窗口内的数字都是最新10个周期内的收盘价。接着利用一个for循环,计算最近10个周期内的收盘价总和。最后计算平均值,这里我们使用了一个三元操作符,确保收集够10个周期的收盘价时,才返回平均值。请注意,我们array创建需要声明是var,确保每个周期内数组的变动会记录下来。
对比于内置函数ta.sma,可以发现两个值是一致的。只是我们构建的函数是从10个周期后才开始呈现。
数组同样可以使用历史引用操作符进行历史的引用。
a = array.new_float(1,close)
runtime.log(a[1])
runtime.log(close[1])
代码发现,数组a和close使用历史引用后,两个值是一致的。
以数组为集合,可以进行统计特征平均值,最小值,最大值,标准差等的获取。
array.avg()求数组中所有元素的平均值array.min()求数组中最小的元素array.max()求数组中最大的元素array.stdev()求数组中所有元素的标准差
array.sum()求数组中所有元素的和
array.median()求数组中元素的中位数
array.mode()求数组中元素的众数
a = array.from(3, 2, 1, 4, 5, 6, 7, 8, 9)
runtime.log("数组a的算数平均:", array.avg(a))
runtime.log("数组a中的最小元素:", array.min(a))
runtime.log("数组a中的最大元素:", array.max(a))
runtime.log("数组a中的标准差:", array.stdev(a))
runtime.log("数组a的所有元素总和:", array.sum(a))
runtime.error("stop")
array.concat(array1,array2): 合并或连接两个数组。
array.copy(): 复制数组。
array.join(array,"连接符号"): 将数组中的所有元素连接成一个字符串。
array.sort(array, order.ascending/order.descending): 按升序或降序排序。
array.reverse(): 反转数组(会修改原始数组)。
array.slice(数组,n1,n2): 对数组进行切片,以n1为开始,以n2为结束,遵循左闭右开的原则进行数据切片。
array.includes(数组,元素): 判断元素。
array.indexof(数组,元素): 返回参数传入的值首次出现的索引。如果找不到该值,则返回 -1。
array.lastindexof(数组,元素): 找到最后一次出现的值。
a = array.from(1, 2, 3, 4, 5, 6)
b = array.from(11, 2, 13, 4, 15, 6)
runtime.log("数组a:", a, ", 数组b:", b)
runtime.log("数组a,数组b连接在一起:", array.concat(a, b))
c = array.copy(b)
runtime.log("复制一个数组b,赋值给变量c,变量c:", c)
runtime.log("使用array.join处理数组c,给每个元素中间增加符号+,连接所有元素结果为字符串:", array.join(c, "+"))
runtime.log("排序数组b,按从小到大顺序,使用参数order.ascending:", array.sort(b, order.ascending)) // array.sort函数修改原数组
runtime.log("排序数组b,按从大到小顺序,使用参数order.descending:", array.sort(b, order.descending)) // array.sort函数修改原数组
runtime.log("数组a:", a, ", 数组b:", b)
array.reverse(a) // 此函数修改原数组
runtime.log("反转数组a中的所有元素顺序,反转之后数组a为:", a)
runtime.log("截取数组a,索引0 ~ 索引3,遵循左闭右开区间规则:", array.slice(a, 0, 3))
runtime.log("在数组b中搜索元素11:", array.includes(b, 11))
runtime.log("在数组a中搜索元素100:", array.includes(a, 100))
runtime.log("将数组a和数组b连接,搜索其中第一次出现元素2的索引位置:", array.indexof(array.concat(a, b), 2), " , 参考观察 array.concat(a, b):", array.concat(a, b))
runtime.log("将数组a和数组b连接,搜索其中最后一次出现元素6的索引位置:", array.lastindexof(array.concat(a, b), 6), " , 参考观察 array.concat(a, b):", array.concat(a, b))
runtime.error("stop")
array函数中还有一些其他的内置函数的用法,大家可以在优宽的Pine语言帮助文档中查询获得。
大家好,今天我们来学习Pine语言中交易函数strategy系列。在学习完所有指标计算和信号判断语法结构后,我们对接真实的市场面对最后一道关卡:交易。期货交易之所以引人入胜,与其独有的T+0交易机制密切相关。一个点的波动就是盈利或者损失,成功的进行交易操作就可以将盈利立即收入囊中。所以怎样在合适的点位进行正确交易方向的操作,就需要strategy系列函数的应用。
在交易信号判断确定后,我们需要立即进行开仓操作,以免错过黄金交易时间。
strategy.entry函数是我们写策略时比较重要的一个下单函数,该函数比较重要的几个参数为:id, direction, qty, when等。
参数:
strategy(pyramiding=2)
strategy.entry("enter long1", strategy.long, 1, when = bar_index==1)
strategy.entry("enter long2", strategy.long, 2, when = bar_index==2)
strategy.entry("enter long3", strategy.long, 3, when = bar_index==3)
设置pyramiding=2,因此只能进行两次的加仓,第三次开仓不成功,设置条件when,在第一根k线,第二根k线开仓,这里也可以设置价格比如open>close等,qty设置开仓的数量。
我们再加上一个开空仓,看看有什么变化。
strategy.entry("enter short1", strategy.short, 1, when = bar_index==4)
可以发现,在开空仓之前,会平掉所有的多头仓位。由于Pine语言脚本持仓只能有一个方向,即如果有和当前持仓方向相反的信号触发会平掉当前持仓再根据信号触发开仓。
strategy.entry函数的具体执行细节受strategy函数调用时的参数设置控制,也可以通过「Pine语言交易类库模版参数」设置控制,Pine语言交易类库模版参数控制的交易细节更多,具体可以查看链接的文档。
strategy.opentrades 未关闭或者继续持有的交易数量。如果没有,则显示0。
strategy.opentrades.entry_bar_index(trade_num) 返回未平仓交易的入场的ID。trade_num (series int)是未平仓交易的交易编号。第一笔交易的编号为零。所以可以用strategy.opentrades-1代替。
strategy.opentrades.entry_price(trade_num) 返回未平仓交易的入场价格。
strategy.opentrades.profit(trade_num) 返回未平仓交易的盈亏。损失表示为负值。
strategy.opentrades.size(trade_num) 返回未平仓交易中的交易方向和合约数量。如果该值>0,则市场仓位为多头。如果该值,则市场仓位为空头。
strategy.opentrades.entry_time(trade_num) 返回未平仓交易入场的UNIX时间。
if bar_index == 1
strategy.entry("Long1", strategy.long)
runtime.log('opentrades',strategy.opentrades)
runtime.log('bar_index',strategy.opentrades.entry_bar_index(0))
runtime.log('entry_price',strategy.opentrades.entry_price(0))
runtime.log('entry_profit',strategy.opentrades.profit(0))
runtime.log('entry_size',strategy.opentrades.size(0))
runtime.log('entry_time',strategy.opentrades.entry_time(0))
strategy.close函数用于平仓指定标识ID的入场持仓仓位。主要参数有:id,when,qty。
参数:
通过一个例子来熟悉这个函数的使用细节:
strategy("close Demo", pyramiding=3)
strategy.entry("long1", strategy.long, 1)
if strategy.opentrades >= 3
// strategy.close("long1") // 多个入场订单,不指定qty参数,全部平仓
// strategy.close() // 不指定id参数,会平掉当前的持仓
// strategy.close("long2") // 如果指定一个不存在的id则什么都不操作
// strategy.close("long1", qty=1) // 指定qty参数平仓
// strategy.close("long1", qty_percent=70) // qty_percent设置50即为平掉long1标识仓位的50%持仓
// strategy.close("long1", qty_percent=80, when=close>open) // 指定when参数
测试策略展示了开始连续三次做多入场,入场标识ID均为“long1”,然后使用strategy.close函数的不同参数设置平仓时回测出的不同结果。可以发现strategy.close这个函数没有参数可以指定平仓下单价格,这个函数主要用于立即以当前市场价格平仓。
strategy.close_all函数用于平掉当前所有持仓。所以strategy.close_all被调用时会平掉当前方向上的所有持仓。strategy.close_all函数的主要参数为:when。
参数:
我们使用一个例子来观察:
strategy.entry("long1", strategy.long, 1, when=bar_index==1)
strategy.entry("long2", strategy.long, 1, when=bar_index==2)
strategy.close_all(when=bar_index==3)
可以发现strategy.close_all这个函数没有参数可以指定平仓下单价格,这个函数主要用于立即以当前市场价格平仓。
strategy.exit函数被用于入场持仓的平仓操作,与该函数不同的是strategy.close和strategy.close_all函数是以当前市场价格立即平仓。strategy.exit函数会根据参数设置进行计划平仓。
参数:
strategy("strategy.exit Demo")
strategy.entry("long1", strategy.long, 1, limit=1)
strategy.entry("long2", strategy.long, 1)
strategy.exit("exit1", "long1", profit=50) // 由于long1入场订单没有成交,因此ID为exit1的出场订单也处于暂待状态,直到对应的入场订单成交才会放置exit1
//strategy.exit("exit2", "long2", qty=1, profit=20) // 指定参数qty,当盈利20的时候,平掉ID为long2的持仓
strategy.exit("exit2", "long2", qty=1), profit=20, loss=20) // 指定参数qty,当盈利20或者亏损20的时候,平掉ID为long2的持仓
strategy.exit("exit2", "long2", qty=1) // 所有参数 'profit', 'limit', 'loss', 'stop', 'trail_points', 'trail_offset' 皆为“NaN”,则命令将失败。
使用实时价模型回测测试,这个测试策略开始执行了2个入场操作(strategy.entry函数),“long1”故意设置了limit参数,挂单价格为1使其无法成交。然后测试条件出场函数strategy.exit。使用了按点数止盈、按价格止盈。价格一跳乘以10作为止盈价差,价格一跳即内置变量syminfo.mintick。例如玻璃和纯碱的价格一跳是20元,而螺纹钢和甲醇等价格一跳是10元。
当然还有strategy.closetrades查询已平仓交易的一些信息,大家也可以尝试下。
strategy.cancel函数用来取消/停用所有预挂单的命令。这些函数strategy.order, strategy.entry , strategy.exit可以产生入场ID。该函数主要参数为:id、when。
参数:
strategy("strategy.cancel Demo",)
strategy.entry("long1", strategy.long, 0.1, limit=1)
strategy.cancel("long1")
strategy.cancel_all函数和strategy.cancel函数类似。取消/停用所有预挂单命令。可以指定when参数。
参数:
strategy("strategy.cancel Demo", pyramiding=3)
strategy.entry("long1", strategy.long, 0.1, limit=1)
strategy.entry("long2", strategy.long, 0.2, limit=2)
strategy.entry("long3", strategy.long, 0.3, limit=3)
strategy.cancel_all()
strategy.order函数的功能、参数设置等几乎与strategy.entry一致,区别为strategy.order函数不受strategy函数的pyramiding参数设置影响,没有下单次数限制。
参数:
strategy(title = "simple strategy order example")
strategy.order("buy", strategy.long, 1, when = open > high[1]) // buy by market if current open great then previous high
strategy.order("sell", strategy.short, 1, when = open < low[1]) // sell by market if current open less then previous low
交易是一门高深的学问,需要考验你的认知,耐心,毅力和决心。你需要根据你的交易理念和策略,选择做日内短线交易或者长期趋势交易,,因此反应在代码里就是你的交易函数的选择和交易参数的使用。本章内容一开始听起来确实让人比较迷惑,因为内容很多,灵活运用比较困难。幸好我们具有优宽平台,免费的代码回测可以帮助你进行足够多次数的试错,从而了解到每个函数的用法,进而不断优化你的量化策略系统。我们下节课再见!
大家好,在前面的课程中。我们完整的学习了Pine语言的语法结构及其交易函数。至此,Pine语言的理论讲解部分告一段落,从今天起,我们开始转向对接真实的期货交易市场,研究怎样利用Pine语言帮助进行量化交易,搭建自己的量化交易系统。
身为一个新手,对于大盘的理解可以用四个字来形容,眼花缭乱。为什么在自己不交易的时候,指标嗖嗖的上涨或者下跌,而自己一旦买入或者卖出,那指标就磨磨蹭蹭,逐笔浮盈的颜色始终在黑色(平价)或者绿色(亏损)转换,有时候会怀疑是否几个亿的资金大盘是否都是在针对自己?于是,寻找不确定性中的确定性变成了我们盈利的突破点所在。
指标作为从历史数据中统计出来的结果,代表着一定的惯性。如果趋势继续存在,那么指标就是在不确定的海洋中,一盏弱小的指引方向的灯塔。纵使灯塔也可能存在于海市蜃楼中,指标也可以作为辅助判断的依据。因此,从今天起,我将带领大家学习量化指标。因此,本部分的内容将对量化指标系统进行一个较为系统的讲解。当然,这部分的内容一方面是在学习怎样利用Pine语言构造量化指标,更重要的是学习这些量化指标的理念。在参考了各类金融软件系统对指标的讲解和网络上各路视频的讲解,可以发现指标的使用方法很多很杂,各类策略有可能还存在冲突的地方,没有一以贯之的黄金策略。因此,本部分的内容将以讲解指标概念和计算方法为关键点,怎样利用指标编写一个完美的交易策略还需要大家对市场有着更为深刻的理解,所以在这部分的课程中,对于指标的策略展示,教学展示的策略都比较简单,仅为教学展示用,不可轻易应用于实盘,仅仅起到一个抛砖引玉的作用。在真实的市场中,需要根据自己的理解,对指标进行更多的优化,才能真正的将这些指标应用于自己的量化交易系统中。
指标系统可以分为趋势指标,反趋势指标,压力支撑指标,量价指标,能量指标和成交量指标等。趋势交易策略,也被称为趋势跟随策略,旨在延续现有的趋势。本节课的内容,我们将以趋势指标为讲述对象,讲解几个示范指标的概念及其在Pine语言中的使用方法。
BBI指标,即多空指标,英文全名为”Bull And Bear lndex”,简称BBI,是一种将不同日数移动平均线加权平均之后的综合指标,属于均线型指标,一般选用3日、6日、12日、24日等4条平均线。在使用移动平均线时,投资者往往对参数值选择有不同的偏好,而多空指标恰好解决了中短期移动平均线的期间长短合理性问题。很明显,在BBI指标中,近期数据较多,远期数据利用次数较少,因而是一种变相的加权计算。由于多空指标是一条混合平均线,所以既有短期移动平均线的灵敏,又有明显的中期趋势特征,适于稳健的投资者。
1.价格位于BBI上方,视为多头市场。 2.价格位于BBI下方,视为空头市场。 3.下跌行情中,若当日收盘价跌破BBI曲线,表示多转空,为卖出信号。 4.上涨行情中,若当日收盘价升越BBI曲线,表示空转多,为买入信号。 5.上升回档时,BBI为支持线,可以发挥支撑作用。 6.下跌反弹时,BBI为压力线,可以发挥阻力作用。
BBI的周期也有多种选择,短线选择较短周期,长线选择较长周期。
首先计算四个均价,然后平均计算BBI,接着利用和close价格的“黄金”或者“死亡”交叉进行买卖信号的判断。
BBI = (ta.sma(close,3)/3 + ta.sma(close,6)/6 + ta.sma(close,12)/12 + ta.sma(close,24)/24)/4
DIF= BBI - close
plot(BBI, title = 'BBI', color=color.blue)
plot(DIF, title = 'DIF', color=histLine > 0 ? color.red : color.green, style=plot.style_histogram)
if ta.crossover(DIF,0)
strategy.entry('long',strategy.long,comment = 'long')
if ta.crossunder(DIF,0)
strategy.entry('short',strategy.short,comment = 'short')
BBI指标,可以综合不同时间段的移动平均线的具体数值,数值更加具体和客观。
使用简单,可以轻松的判断多空趋势。
缺点 BBI的本质上是对MA的一种改进,所以,也具有一些类似于MA的缺点: 1、指标信号的滞后性。 2、指标信号的频发现象,特别在趋势不明朗时,这种现象更为严重。 3、指标单一。
三重指数平滑平均线(TRIX)属于中长线指标。它过滤掉许多不必要的波动来反映股价的长期波动趋势。TRIX指标又叫三重指数平滑移动平均指标,其英文全名为“Triple Exponentially Smoothed Average”,是一种研究股价趋势的长期技术分析工具。与BBI理念类似,TRIX使用EMA作为均值的计算方法。
MACD(Moving Average Convergence and Divergence)在我们前面的课程中多次被提到,它 是利用收盘价的短期(常用为12日)指数移动平均线与长期(常用为26日)指数移动平均线之间的聚合与分离状况,对买进、卖出时机作出研判的技术指标。
一、差离值(DIF值):
先利用收盘价的移动平均值(12日/26日)计算出差离值。EMA是指数平均数指标。
DIF的计算方法为:
DIF = EMA(close,12) - EMA(close,26)
二、讯号线(DEM值,又称MACD值):
计算出DIF后,会再画一条“讯号线”,通常是DIF的9日移动平均值。
DEA = EMA(DIF,9)
三、柱形图或棒形图(histogram / bar graph):
接着,将DIF与DEM的差画成“柱形图”(MACD bar / OSC)。
OSC = DIF - DEM
首先利用内置函数ta.macd计算出来三个指标值,macdLine(DIF), signalLine(DEA), histLine(OSC)并进行画图展示。接着利用histLine进行开平仓的信号判断,当上穿0线(crossover)进行买入,当下穿(crossunder)0线进行卖出。
[macdLine, signalLine, histLine] = ta.macd(close, 12, 26, 9)
plot(macdLine, title = 'macdLine', color=color.blue)
plot(signalLine, title = 'signalLine', color=color.orange)
plot(histLine, title = 'histLine', color=histLine > 0 ? color.red : color.green, style=plot.style_histogram)
if ta.crossover(histLine,0)
strategy.entry('long',strategy.long,comment = 'long')
if ta.crossunder(histLine,0)
strategy.entry('short',strategy.short,comment = 'short')
具有滞后性。当行情忽上忽下幅度太小或盘整时,按照信号进场后随即又要出场,买卖之间可能没有利润,也许还要赔点价差或手续费。在同时,一旦行情迅速大幅涨跌,MACD不会立即产生信号,此时,MACD无法发生作用。
DMA指标是指平行线差指标,是依据快慢两条移动平均线的差值情况来分析价格趋势的一种技术分析指标。DMA只是以收盘价(CLOSE)作为唯一的数据源,进行平均算数。DMA和MACD的区别是DMA利用MA计算,而MACD利用EMA计算。
DIF:MA(CLOSE,N1)-MA(CLOSE,N2);
DIFMA:MA(DIF,M);
输出DIF:收盘价的N1日简单移动平均-收盘价的N2日简单移动平均;
输出均线DIF:DIF的M日简单移动平均;
1、DIF线向上穿破DIFMA,即买入信号; 2、DIF线向下穿破DIFMA,即卖出信号。
SAR
SAR指标又叫抛物线指标或停损转向操作点指标,其全称叫“Stop and Reverse,缩写SAR”,是一种简单易学、比较准确的中短期技术分析工具。
这种指标与移动平均线的原理颇为相似,属于价格与时间并重的分析工具。由于组成SAR的点以弧形的方式移动,故称“抛物转向”。
从SAR指标英文全称知道它有两层含义。一是“stop”,即停损、止损之意,这就要求投资者在买卖某个品种之前,先要设定一个止损价位,以减少投资风险。而这个止损价位也不是一直不变的,它是随着价格的波动止损位也要不断的随之调整。目标是既可以有效地控制住潜在的风险,又不会错失赚取更大收益的机会。 SAR指标的英文全称的第二层含义是“Reverse”,即反转、反向操作之意,这要求投资者在决定投资前先设定个止损位,当价格达到止损价位时,投资者不仅要对前期买入的品种进行平仓,而且在平仓的同时可以进行反向做空操作,以谋求收益的最大化。
以计算日SAR为例,计算方法如下: 先选定时间,判断价格是在上涨还是在下跌: 若是看涨,则进场第一天的SAR必须是近期内的最低价,若是看跌则进场第一天的SAR必须是近期内的最高价; 第二天的SAR则为第一天的最高价(看涨时)或最低价(看跌时)与第一天的SAR的差距乘上调整系数,再加上第一天的SAR就可求得。 按逐步递推的方法,每日的SAR可日纳如下: SAR(N)= SAR(N-1)+ AF * [ EP(N-1)-SAR(N-1)] 其中SAR(N)为第N日的SAR值,AF是调整系数,EP为极点价; 第一个调整系数AF为0.02,若每隔一天的最高价比前一天的最高价还高,则AF递增0.02,若未创新高,则AF沿用前一天的数值,但调整系数最高不超过0.2; 若是买进期间,计算出某日的SAR比当日或前一日的最低价还高,则应以当日或者前一日的最低价为某日之SAR,卖出期间也对应服从类似原则。
可以使用Pine语言内置函数或者自定义函数编写一下:
sar = ta.sar(0.02, 0.02, 0.2)
plot(sar, style=plot.style_cross, linewidth=3)
if ta.crossover(close,sar)
strategy.entry('long',strategy.long,comment = 'long')
if ta.crossunder(close,sar)
strategy.entry('short',strategy.short,comment = 'short')
同样,SAR也具有滞后性,不能及时处理突发的大盘变化。
在我们上述的指标之外,趋势指标还包括动量指标(MTM),TWR宝塔线指标,DDI 方向标准离差指数,大家有兴趣都可以研究一下。总体来说,这些指标都试图寻找某一时间段内的惯性趋势,在大盘突破这些确定性趋势的时候,做出进场的信号。因为这些指标都是以一定时间段反应后,才做出的决断,在一方面,都存在滞后性的问题;在另一方面,也对市场的突发情形不能做出及时的判断。因此,针对不同的品种需要设置不同的策略周期,比如沥青日内波动比较剧烈,策略周期可以设置小一点;
使用MACD策略,对于沥青以小时为策略周期的回测收益:
对于沥青以天为策略周期的回测收益:
而玻璃的日内波动比较小,策略周期可以设置大一点。
使用MACD策略,对于玻璃以小时为策略周期的回测收益:
对于玻璃以天为策略周期的回测收益:
当然,这些品种的特点并不是固定不变的,你需要及时跟踪市场趋势,做出及时的参数调整和变化。正如传言而言,一个好的量化工程师每天的代码量不超过三行,但是“行行千金”。努力吧,少年!我们下节课再见!
大家好,今天我们继续量化指标的学习。在金融技术分析指标中,反趋向类指标,也就是震荡指标,是一个重要的分类。其中KDJ(随机指标)、RSI(相对强弱指标)、CCI(顺势指标)等指标都是各类证券分析软件中的常用指标。其实反趋向类指标和趋向类指标一样,都是判断价格走势趋向的指标,但是使用了逆向思维。反趋势提供一种与趋势跟踪同样有效的系统性的、保守的交易框架,但使用完全相反的方法。与趋势跟踪系统相比,反趋势系统通常交易区间更短,成功率更高一些,成功/失败比率更小一些。经过统计发现,一个典型的反趋势策略将会比趋势跟踪策略交易更频繁一些,成功率在55%-60%之间,成功交易与失败交易的比率小于1.5。因此,在一定程度上可以认为,在长期趋势较为明显的情况下,趋势指标是比较适合的;而长期趋势不明显,日内波动比较大的情况下,反趋势策略比较适合。
BIAS乖离率是用价格指数与移动平均线的比值关系,来描述价格与移动平均线之间的偏离程度。乖离率功能主要是通过测算价格在波动过程中与移动平均线出现偏离程度,从而得出价格在剧烈波动时因偏离移动平均趋势而造成可能的回挡或反弹,以及价格在正常波动范围内移动而形成继续原有势的可信度。
BIAS(N) = (收盘价 - N周期移动平均价) / N周期移动平均价 * 100
(1)若价格在移动平均线之上,乖离率为正,反之为负;当价格与平均线相同,乖离率为零; (2)正乖离率值越大,说明价格向上偏离移动平均线的程度越大,有可能回档下调; (3)负乖离值越小,表明价格向下偏离移动平均线的程度越大,随时可能反弹; (4)多头市场的狂涨与空头市场的狂跌会使乖高率达到意想不到的百分比,但是出现次数极少,时间亦短。
我们这优宽平台进行一下乖离率指标的复现,由于Pine语言没有现成的内置函数,我们可以自己计算。首先设置研究周期n,接着计算今日收盘价和N个周期收盘价的移动平均值之差,然后除以周期移动平均值就可以获得,然后利用画图函数在图表中呈现出来。
bias5 = (close - ta.sma(close,5))/ta.sma(close,5)*100
bias10 = (close - ta.sma(close,10))/ta.sma(close,10)*100
bias20 = (close - ta.sma(close,20))/ta.sma(close,20)*100
plot(bias5, title = 'bias5')
plot(bias10, title = 'bias10')
plot(bias20, title = 'bias20')
36乖离指标考虑不同周期的移动平均线之间的差距,衡量短期和中期投资者获利的相互状态,进而评估短、中期投资者对后市的看法。不同周期移动平均线之间的差距称为乖离,3日平均数值与6日平均数值之间的差值为B36,6日平均数值与12日平均数值之间的差值为B612。
【计算方法】 B36 = 最近3日的收盘价之和 / 3 - 最近6日的收盘价值和 / 6 B612 = 最近3日的收盘价之和 / 6 - 最近6日的收盘价值和 / 12
ROC(RATE OF CHANGE),中文名称:变动率指标。该指标测量价格动量,可以用来监视常态性和极端性两种行情,对买卖信号提供强有力的参考。
ROC = (今收盘 - 前N周期收盘) / 前N周期收盘 * 100
OSC摆动量,反映的是价格与移动平均价的偏离的绝对距离,OSC的构造思想同Bias是相同的。
OSC = 当周期收盘价 - N周期的平均价
CCI(Commodity Channel Index),中文名称:顺势指标。CCI指标主要是用来对付极端行情的,适合于快进快出的短线。
计算方法是商品的典型价格与其简单移动平均线之间的差值除以典型价格的平均绝对偏差。该指数按0.015的倒数进行缩放,以提供更多可读的数字。
TP = (最高价 + 最低价 +收盘价) / 3 MA = 最近N周期TP的累计和 / N MD = (最近N周期(MA - TP)累计和) / N CCI(N) = (TP - MA) / 0.015*MD 说明:N值为14
(1)CCI的常态区为 -100至+100; (2)当CCI从0+100的正常范围内,由下往上突破+100时,价格有可能出现强势上涨,是买入的时机;当CCI从+100之上,由上往下跌破+100,价格短线有可能出现回调,是卖出的时机; (3)当CCI从0-100的正常范围内,由上往下跌破-100时,价格有可能出现弱势下跌,是抛出的时机。当CCI从-100的下方,由下往上突破-100时,有可能出现反弹,可逢低买入; (4)当价格创出新高,而CCI没有同步创出新高时,顶背离出现,短线价格有可能出现回挡,可逢高卖出; (5)当价格创出新低,而CCI没有同步创出新低时,底背离出现,短线价格有可能出现反弹,可逢低买入。
cci = ta.cci(close, 14)
plot(cci, title = 'cci')
hline(-100, title = 'bottom_line')
hline(0, title = 'horizon_line')
hline(100, title = 'up_line')
KDJ指标是目前中国金融市场最普及的指标之一,全称为随机指标(Stochastics),它综合了动量观念、强弱指标及移动平均线的优点,是波段操作的有力武器。
以计算日KDJ为例,计算方法如下:
对每一交易日求RSV(未成熟随机值)
RSV = (收盘价-最近N日最低价) / (最近N日最高价-最近N日最低价) × 100
K线 : K值 = (M1-1)/M1 * 前一日K值 + 1/M1 * 当日RSV ;
D线 :K值 = (M2-1)/M2 * 前一日D值 + 1/M2 * 当日K值 ;
J线 : 3 × 当日K值 - 2 × 当日D值
参数:N、M1、M2 天数,一般取9、3、3
(1)D > 80,超买;D < 20,超卖;J > 100%超买;J < 10%超卖;
(2)线K向上突破线D,买进信号;线K向下跌破线D,卖出信号;
(3)线K与线D的交叉发生在70以上,30以下,才有效;
(4)KD指标不适于发行量小,交易不活跃的品种;
(5)KD指标对大盘和热门大盘品种有极高准确性。
hgst = ta.highest(high,9)
lwst =ta.lowest(low,9)
rsv=(close-lwst)*100/(hgst-lwst)
k = 0.0
d = 0.0
j = 0.0
k := (rsv+2*nz(k[1]))/3
d := (k+2*nz(d[1]))/3
j := 3*k - 2*d
//Step Three: plotting
plot(k,title = 'k', color=color.blue)
plot(d,title = 'd',color = color.orange)
plot(j,title = 'j',color =color.black)
hline(80,color=color.red,linestyle = hline.style_dashed, linewidth =1)
hline(20,color=color.green, linestyle = hline.style_dashed,linewidth = 1)
if (k <20 and d <20 and k>d and k[1] <d[1])
strategy.entry('long', strategy.long)
if (k >80 and d >80 and k<d and k[1] > d[1])
strategy.close('long')
Slowed KD是在KD的基础上,对D再进行一次平滑,选择的平滑工具是移动平均,而不是指数平滑。Slowed KD中的K就是KD中的D,Slowed KD中的D是KD中的D的值的移动平均;经过平滑的比未经过平滑的慢,所以Slowed KD同KD的本质没有什么不同。
依据前人经验,大部分反趋势模型寻找卖掉短期内超买的和买入短期内超卖的机会。这些目标有点象在等待橡皮筋拉伸到它的极限的时机,然后打赌他们会回弹到一个相对松弛的状态。这些行为使得反趋势交易模型在市场缺乏方向性或者波动性很大时斩获颇丰,并能够在市场拐点出现的时候迅速反应。反趋势模型的缺点是在稳定的、趋势性较强的市场环境中他们经常交易不顺,也就是常说的‘赢小钱亏大钱’。
一个短期的反趋势系统想要成功,价格必须要在指数的长期趋势或者某些其他的显著的价格点附近不断的前前后后摇摆。这种市场反应意味着市场价格移动包含足够的噪音以及波动性,从而带来反趋势交易的盈利机会。
大家好,今天我们继续量化指标的学习:压力支撑指标。我们常常可以看见价格波动至某一位置,就不再按原有趋势运动,好像存在着某种力量,这就是我们经常讲到的压力和支撑,股价波动的趋势往往会在这些位置发生变化,例如趋势的延缓、加速或反转等。压力和支撑实际上受供求关系的影响,在上涨的过程中,随着获利盘的增多卖盘的供应逐渐大于买盘的需求,从而影响了价格的继续上行,形成了压力;而下跌的过程中,随着价格的降低买盘的需求逐渐强于卖盘的供应,从而价格上形成向上的支撑推动力。
压力线:当价格上涨到某一个价位时,就会产生对价格起到压制作用,这些高点价位之间的可连续称之为压力线。
支撑线:当价格下跌到某一低点后开始反弹,在该价位附近有支撑,这些低点之间的连续称之为支撑线。
压力和支撑的互相转化,在支撑位附近,如果有利空消息或有大资金撤离等因素刺激,跌破有效支撑后,将会上顺势寻找下一个支撑位,而该支撑位将转换成下跌后的上涨阻力位。同样的阻力位附近,如果利好消息出台或有大资金进场等因素刺激,形成有效的突破后,该阻力位将转化为上涨后一个下跌的支撑位。压力与支撑的判断分析是技术分析中非常重要的依据之一。阻力的有效突破往往是行的上涨阶段的开始,支撑的有效跌破也是新的下跌的阶段的开始。如果把握好压力和支撑的运动规律,可以较好的的把握每一次的买入和卖出的时机,从而得到较好的回报,适合各种行情。
Bollin布林线是一个路径型指标,由上限和下限两条线,构成一个带状的路径。价格超越上限时,代表超买,价格超越下限时,代表超卖。布林线指标的超买超卖作用,只能运用在横向整理的行情。
中线MB = N周期移动平均收盘价
偏移值 = P * N周期收盘价的标准差
上轨UP(阻力线) = 中线 + 偏移值
下轨DOWN(支撑线) = 中线 - 偏移值
参数:N为周期数;P为乘数,如果假设价格波动服从正态分布,P为设置为3。
(1)布林线利用波带显示价格的安全高低价位; (2)价格向上穿越支撑线,买入信号; (3)价格向上穿越阻力线,卖出信号; (4)当易变性变小,而波带变窄时,激烈的价格波动有可能马上发生; (5)高低点穿越上轨或下轨,立刻又回到波带内会有短期回档或短期反弹发生; (6)波带的移动对寻找目标值有很大帮助。
在优宽平台进行一下指标的复现,首先使用参数设置周期和乘数,接着使用布林带的内置函数计算中线,上线阻力位和下线支撑位,使用plot函数在图表中进行三条线的呈现;来看一下指标的使用,当收盘价突破阻力位时,代表上涨趋势的来临,可以开多仓;反之,收盘价跌破支撑位,可以开空仓。
看一下回测结果,回测收益为正,证明该指标具有一定的参考意义。在图像中,可以看到它的作用周