商品期货量化交易-TradingviewPine语言基础课程(二十三):量化实战:吊灯退出策略

Author: ianzeng123, Created: 2023-04-13 11:54:35, Updated:

大家好,今天我们进入Pine语言期货市场量化交易最后一个板块:实战策略编写。Pine语言的功能确实很强大,里面的内置函数基本涵盖了金融常用的量化指标和函数,但是直接使用成熟的指标还是不能灵活的应对中国的期货市场的不同品种。每个品种都有它不同的品性,应该结合自己的理念,运用更加细腻的逻辑编写不同品种的交易策略。

目前对大家来说,可能灵活的使用Pine语言还具有一定的距离。大家通过对于期货大盘的熏陶,可能摸索了一些不成熟的交易理念与想法,但是想真正的转化成为成熟的策略,依然觉得细腻度和成熟度还具有差距。因此,本部分的结尾课程,我将带领大家细细剖析一些量化策略,了解怎样使用Pine语言将自己的交易理念进行代码化,帮助大家真正使用Pine语言对照中国的期货市场,编写出合适的量化策略。本部分的内容初步计划为两个实战策略的讲解:第一节内容为成熟的指标的变化策略;第二节内容为多个指标结合的策略,帮助大家更好的理解指标的变化以及灵活运用。

策略介绍

本节课介绍的策略为吊灯退出策略。吊灯退出指标在某种程度上可视为ATR指标的延伸。吊灯退出指标是一个基于波动性的指标,使交易者能够等到出现明确趋势反转时再进行交易。对于信息不透明的散户来说,期货趋势中明显的反转需要人为的判断,所以只能被动的开展“追涨杀跌”,稍有不慎,下单将会被套牢,出于不想亏损的心理,扛单占据了大部分的时间,而一旦扛单被解套,一点点小盈利散户就抓紧时间平仓,错过了更大盈利的可能性。通过使用吊灯退出指标,交易者将能够避免过早平仓,实现最大的回报。

吊灯退出指标由全球公认平仓策略专家 Chuck Le Beau 创造。 但此指标和与之相关的交易系统却由 Alexander Elder 通过其在 2002 年出版的《Come Into My Trading Room》一书介绍给交易者和投资者。此指标因其与房间天花板上的吊灯相似而得名。

img

策略原理

吊灯退出指标基于以下原理:当资产价格背离主要趋势变动的距离达到平均波动幅度的三倍时就很可能发生趋势反转。该指标是利用指定时间范围内的 ATR(真实波动幅度均值) 值创建的。 除了ATR以外,在计算中还使用了资产在特定时间范围内最高的高点和最低的地点价格。在使用移动窗口周期进行分析时,建议使用 22 天的时间范围输入。 这是因为金融市场每个月有 22 个交易日。 为了确保平滑的效果并过滤短期波动或噪声,建议在计算中使用22天的价格水平。对于其他移动窗口周期,我们可以根据反复参数试验的结果确定使用的时间范围输入。 这个方面并没有硬性的规则。就像前面描述的一样,吊灯退出指标的主要目标是在正确的时间提醒交易者即将发生趋势反转。因此,对于多头头寸和空头头寸,吊灯退出指标的计算方式不同。

在上行趋势中,可使用如下公式计算吊灯退出指标:

  • 多头突破平仓 = 特定时间范围内最高的高点 – 3*特定时间范围内的ATR。

在下行趋势中,可使用如下公式计算灯笼止损指标:

  • 空头突破平仓 = 特定时间范围内最低的低点 + 3*特定时间范围 内的ATR。

倍数值3是指吊灯退出指标的倍数,交易者可以更改此倍数。虽然并没有禁止使用不同的时间范围,但对于上涨的移动周期窗口和下跌的移动周期窗口,大部分交易者还是会使用相同的时间范围。计算出的值(日间、每日、每周或每月)在价格图表上绘制成一条线。 根据上述公式,可以推测出在下行趋势中,吊灯退出线将高于该价格线。相反,在上行趋势中,吊灯退出线将低于价格线。如果考虑了资产隐含的波动幅度,则可以更改吊灯退出指标的倍数。更大的时间范围则会延迟平仓,因而会稀释指标的作用。在交易隐含波动幅度(市场预期的资产价格涨跌幅度)较大的期货基数时,需要更大的倍数。 在金融市场上,交易者在下行趋势中使用较小倍数的情况并不罕见,因为价格下跌的速度一般会更快。

计算方法

  1. 计算真实波幅倍数(ATR*乘数);
  2. 计算longstop和shortstop;
  3. 根据收盘价和longstop、shortstop关系,判断突破信号;
  4. 根据突破信号,进行开平仓操作。

策略源码

study("吊灯退出", overlay=true)

length = input.int(12, title="ATR周期", minval=11, maxval=33)
mult = input.int(3, title="ATR乘数", minval=1, maxval=5)
showLabels = input.bool(title="显示 Buy/Sell 标签 ?", defval=true)
useClose = input.bool(title="使用收盘价作为极值点 ?", defval=true)

//计算真实波幅倍数
atr = mult * ta.atr(length)

//使用收盘价作为极值点,返回移动窗口周期内的收盘价最大值,不使用的话,返回移动窗口周期内的最高值(high)的最大值,然后减去atr
longStop = (useClose ? ta.highest(close, length) : ta.highest(length)) - atr 
//如果再开始的时候,longStop[1]是null,返回longStop
longStopPrev = nz(longStop[1], longStop)
//昨日的收盘价大于longStopPrev,说明没有突破longStopPrev,继续上升的趋势,返回longStop和longStopPrev的最大值(为下一日做准备),如果昨日向下突破longStopPrev,返回最新的longstop,这是一个不断更新longstop的过程
longStop := close[1] > longStopPrev ? math.max(longStop, longStopPrev) : longStop

//使用收盘价作为极值点,返回移动窗口周期内的收盘价最小值,不使用的话,返回移动窗口周期内的最低值(low)的最小值,然后加上atr
shortStop = (useClose ? ta.lowest(close, length) : lowest(length)) + atr
//如果再开始的时候,shortStop[1]是null,返回shortStop
shortStopPrev = nz(shortStop[1], shortStop)
//昨日的收盘价小于shortStopPrev,说明没有突破shortStopPrev,继续下降的趋势,返回shortStop和shortStopPrev的最小值(为下一日做准备),如果昨日向上突破shortStopPrev,返回最新的shortStop,这是一个不断更新shortStop的过程
shortStop := close[1] < shortStopPrev ? math.min(shortStop, shortStopPrev) : shortStop

var int dir = 1
//两个三元表达式,下降过程中,如果close向上突破shortStopPrev,应该空头反转开多,返回1;
//否则如果close没有突破shortStopPrev,应该继续空头持有,返回-1;
//上升过程中,如果close向下突破longStopPrev,应该多头反转开空,返回-1;
//否则close没有突破longStopPrev,应该继续多头持有,返回1
//精髓就在于后续是一个var dir,会保留先前的dir状态,只要不进行突破,就会保留原始的var值
//转空是一个1到-1;转多是一个-1到1
dir := close > shortStopPrev ? 1 : close < longStopPrev ? -1 : dir

var color longColor = color.green
var color shortColor = color.red

//空头反转开多,dir由-1转为1,多头止损开启
//画线
longStopPlot = plot(dir == 1 ? longStop : na, title="Long Stop", style=plot.style_linebr, linewidth=2, color=longColor)
buySignal = dir == 1 and dir[1] == -1
//画圆圈
plotshape(buySignal ? longStop : na, title="Long Stop Start", location=location.absolute, style=shape.circle, size=size.tiny, color=longColor, transp=0)
//画箭头
plotshape(buySignal and showLabels ? longStop : na, title="Buy Label", text="Buy", location=location.absolute, style=shape.labelup, size=size.tiny, color=longColor, textcolor=color.white, transp=0)

//多头反转开空,dir由1转为-1,空头止损开启
//画线
shortStopPlot = plot(dir == 1 ? na : shortStop, title="Short Stop", style=plot.style_linebr, linewidth=2, color=shortColor)
sellSignal = dir == -1 and dir[1] == 1
//画圆圈
plotshape(sellSignal ? shortStop : na, title="Short Stop Start", location=location.absolute, style=shape.circle, size=size.tiny, color=shortColor, transp=0)
//画箭头
plotshape(sellSignal and showLabels ? shortStop : na, title="Sell Label", text="Sell", location=location.absolute, style=shape.labeldown, size=size.tiny, color=shortColor, textcolor=color.white, transp=0)

//画出中间价
midPricePlot = plot(ohlc4, title="ohlc4", style=plot.style_circles, linewidth=0, display=display.none, editable=false)

//多头信号,开多仓;空头信号,开空仓
if buySignal
    strategy.entry("Enter Long", strategy.long)
else if sellSignal
    strategy.entry("Enter Short", strategy.short)

策略评价

  • 优点 允许交易者以可以忽略的风险等到最后一个点再交易。 允许使用多个指标创建先进的策略。 经验丰富的交易者可以过滤掉错误的信号,从而放心地交易货币。

  • 缺点 需要有足够的知识和实践经验才能更改吊灯退出的倍数值。

通过细细剖析策略源码,可以感到一个形容词“精巧”。通过简单的代码编写,对于突破信号的设计和转换,完成对多头和空头的对调开仓。策略原理我相信大家都可以理解,重要的是怎样使用精确简洁的语言讲自己的交易理念进行代码化呈现,这是我希望大家和我一起学习的事情。本节课的内容讲述完毕,我们下节课再见!


更多内容