量化策略:SuperTrend策略
免责声明:本文所有内容仅用于交流学习,不构成任何投资建议!投资有风险,入市需谨慎!
策略介绍
SuperTrend策略是一种基于技术分析的趋势跟踪交易方法,通过动态计算价格通道来识别市场趋势方向,并生成清晰的买入和卖出信号。其核心思想是“追随趋势”,旨在捕捉中长期的价格动能,同时通过波动率调整过滤市场噪音。
一、策略原理
SuperTrend指标结合了平均真实波幅(ATR)和移动平均线的概念,形成一个动态支撑阻力通道。计算公式如下:
基础线:通常选择中期均线(如10期简单移动平均线)或中轨(最高价与最低价的平均值)。
通道上下轨:
上轨 = 基础线 + N × ATR
下轨 = 基础线 - N × ATR
(N为倍数参数,常用2~3倍,ATR周期常设为10)
信号生成:
当价格突破上轨时,趋势转为看涨,指标线切换至下轨下方,发出买入信号。
当价格跌破下轨时,趋势转为看跌,指标线切换至上轨上方,发出卖出信号。
二、交易规则
做多条件:SuperTrend指标线位于K线下方(显示为绿色或特定颜色),持仓或开仓。
做空条件:指标线位于K线上方(显示为红色),平仓或反手做空(适用于双向市场)。
止损止盈:指标线本身可作为移动止损线,当价格反向突破指标线时自动离场。
三、策略特点
优势:
直观清晰:通过颜色变化直接展示趋势方向,降低主观判断干扰。
适应波动:ATR机制使通道宽度随市场波动率调整,在震荡市中减少假信号。
趋势跟踪能力强:在单边行情中能有效捕捉主要利润段。
局限性:
滞后性:基于历史数据计算,信号发出时趋势可能已运行一段。
震荡市亏损:在窄幅盘整中可能频繁触发反向信号,导致连续止损。
参数敏感:ATR倍数和周期需根据交易品种特性优化,无普适参数。
四、应用建议
SuperTrend策略适用于趋势明显的股票、期货或外汇市场,常与其他指标(如RSI、MACD)结合过滤信号。例如,在SuperTrend看涨时,仅当动量指标同步走强才入场。实践中需通过回测确定参数,并严格执行止损纪律。
结语
SuperTrend以其简洁逻辑和可视化优势,成为中长线趋势交易者的常用工具。然而,任何单一策略均无法适应所有市场环境,结合多维度分析和风险管理,方能提升策略的稳健性。
策略实现
【 扫描文末二维码加入星球获取完整源码 】
源码
/*backteststart: 2019-08-01 00:00:00end: 2020-03-11 00:00:00period: 15mbasePeriod: 5mexchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD"}]*/// 全局变量var OpenAmount = 0 // 开仓后持仓的数量var KeepAmount = 0 // 保留仓位var IDLE = 0var LONG = 1var SHORT = 2var COVERLONG = 3var COVERSHORT = 4var COVERLONG_PART = 5var COVERSHORT_PART = 6var OPENLONG = 7var OPENSHORT = 8var State = IDLE// 交易逻辑部分function GetPosition(posType) {var positions = _C(exchange.GetPosition)/*if(positions.length > 1){throw "positions error:" + JSON.stringify(positions)}*/var count = 0for(var j = 0; j < positions.length; j++){if(positions[j].ContractType == Symbol){count++}}if(count > 1){throw "positions error:" + JSON.stringify(positions)}for (var i = 0; i < positions.length; i++) {if (positions[i].ContractType == Symbol && positions[i].Type === posType) {return [positions[i].Price, positions[i].Amount];}}Sleep(TradeInterval);return [0, 0]}function CancelPendingOrders() {while (true) {var orders = _C(exchange.GetOrders)for (var i = 0; i < orders.length; i++) {exchange.CancelOrder(orders[i].Id);Sleep(TradeInterval);}if (orders.length === 0) {break;}}}function Trade(Type, Price, Amount, CurrPos, OnePriceTick){ // 处理交易if(Type == OPENLONG || Type == OPENSHORT){ // 处理开仓exchange.SetDirection(Type == OPENLONG ? "buy" : "sell")var pfnOpen = Type == OPENLONG ? exchange.Buy : exchange.Sellvar idOpen = pfnOpen(Price, Amount, CurrPos, OnePriceTick, Type)Sleep(TradeInterval)if(idOpen) {exchange.CancelOrder(idOpen)} else {CancelPendingOrders()}} else if(Type == COVERLONG || Type == COVERSHORT){ // 处理平仓exchange.SetDirection(Type == COVERLONG ? "closebuy" : "closesell")var pfnCover = Type == COVERLONG ? exchange.Sell : exchange.Buyvar idCover = pfnCover(Price, Amount, CurrPos, OnePriceTick, Type)Sleep(TradeInterval)if(idCover){exchange.CancelOrder(idCover)} else {CancelPendingOrders()}} else {throw "Type error:" + Type}}function SuperTrend(r, period, multiplier) {// atrvar atr = talib.ATR(r, period)// baseUp , baseDownvar baseUp = []var baseDown = []for (var i = 0; i < r.length; i++) {if (isNaN(atr[i])) {baseUp.push(NaN)baseDown.push(NaN)continue}baseUp.push((r[i].High + r[i].Low) / 2 + multiplier * atr[i])baseDown.push((r[i].High + r[i].Low) / 2 - multiplier * atr[i])}// fiUp , fiDownvar fiUp = []var fiDown = []var prevFiUp = 0var prevFiDown = 0for (var i = 0; i < r.length; i++) {if (isNaN(baseUp[i])) {fiUp.push(NaN)} else {fiUp.push(baseUp[i] < prevFiUp || r[i - 1].Close > prevFiUp ? baseUp[i] : prevFiUp)prevFiUp = fiUp[i]}if (isNaN(baseDown[i])) {fiDown.push(NaN)} else {fiDown.push(baseDown[i] > prevFiDown || r[i - 1].Close < prevFiDown ? baseDown[i] : prevFiDown)prevFiDown = fiDown[i]}}var st = []var prevSt = NaNfor (var i = 0; i < r.length; i++) {if (i < period) {st.push(NaN)continue}var nowSt = 0if (((isNaN(prevSt) && isNaN(fiUp[i - 1])) || prevSt == fiUp[i - 1]) && r[i].Close <= fiUp[i]) {nowSt = fiUp[i]} else if (((isNaN(prevSt) && isNaN(fiUp[i - 1])) || prevSt == fiUp[i - 1]) && r[i].Close > fiUp[i]) {nowSt = fiDown[i]} else if (((isNaN(prevSt) && isNaN(fiDown[i - 1])) || prevSt == fiDown[i - 1]) && r[i].Close >= fiDown[i]) {nowSt = fiDown[i]} else if (((isNaN(prevSt) && isNaN(fiDown[i - 1])) || prevSt == fiDown[i - 1]) && r[i].Close < fiDown[i]) {nowSt = fiUp[i]}st.push(nowSt)prevSt = st[i]}var up = []var down = []for (var i = 0; i < r.length; i++) {if (isNaN(st[i])) {up.push(st[i])down.push(st[i])}if (r[i].Close < st[i]) {down.push(st[i])up.push(NaN)} else {down.push(NaN)up.push(st[i])}}return [up, down]}var preTime = 0function main() {exchange.SetContractType(Symbol)while (1) {var r = _C(exchange.GetRecords)var currBar = r[r.length - 1]if (r.length < pd) {Sleep(5000)continue}var st = SuperTrend(r, pd, factor)$.PlotRecords(r, "K")$.PlotLine("L", st[0][st[0].length - 2], r[r.length - 2].Time)$.PlotLine("S", st[1][st[1].length - 2], r[r.length - 2].Time)if(!isNaN(st[0][st[0].length - 2]) && isNaN(st[0][st[0].length - 3])){if (State == SHORT) {State = COVERSHORT} else if(State == IDLE) {State = OPENLONG}}if(!isNaN(st[1][st[1].length - 2]) && isNaN(st[1][st[1].length - 3])){if (State == LONG) {State = COVERLONG} else if (State == IDLE) {State = OPENSHORT}}// 执行信号var pos = nullvar price = nullif(State == OPENLONG){ // 开多仓pos = GetPosition(PD_LONG) // 检查持仓// 判断是不是 满足状态,如果满足 修改状态if(pos[1] >= Amount){ // 持仓超过或者等于参数设置的 开仓量Sleep(1000)$.PlotFlag(currBar.Time, "开多仓", 'OL') // 标记OpenAmount = pos[1] // 记录开仓数State = LONG // 标记为 做多状态continue}price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2 // 计算价格Trade(OPENLONG, price, Amount - pos[1], pos, PriceTick) // 下单函数 (Type, Price, Amount, CurrPos, PriceTick)}if(State == OPENSHORT){ // 开空仓pos = GetPosition(PD_SHORT) // 检查持仓if(pos[1] >= Amount){Sleep(1000)$.PlotFlag(currBar.Time, "开空仓", 'OS')OpenAmount = pos[1]State = SHORTcontinue}price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2Trade(OPENSHORT, price, Amount - pos[1], pos, PriceTick)}if(State == COVERLONG){ // 处理平多仓pos = GetPosition(PD_LONG) // 获取持仓信息if(pos[1] == 0){ // 判断持仓是否为 0$.PlotFlag(currBar.Time, "平多仓", '----CL') // 标记State = IDLEcontinue}price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2Trade(COVERLONG, price, pos[1], pos, PriceTick)}if(State == COVERSHORT){ // 处理做多仓pos = GetPosition(PD_SHORT)if(pos[1] == 0){$.PlotFlag(currBar.Time, "平空仓", '----CS')State = IDLEcontinue}price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2Trade(COVERSHORT, price, pos[1], pos, PriceTick)}if(State == COVERLONG_PART) { // 部分平多仓pos = GetPosition(PD_LONG) // 获取持仓if(pos[1] <= KeepAmount){ // 持仓小于等于 保持量,本次平仓完成$.PlotFlag(currBar.Time, "平多仓,保留:" + KeepAmount, '----CL') // 标记State = pos[1] == 0 ? IDLE : LONG // 更新状态continue}price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2Trade(COVERLONG, price, pos[1] - KeepAmount, pos, PriceTick)}if(State == COVERSHORT_PART){pos = GetPosition(PD_SHORT)if(pos[1] <= KeepAmount){$.PlotFlag(currBar.Time, "平空仓,保留:" + KeepAmount, '----CS')State = pos[1] == 0 ? IDLE : SHORTcontinue}price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2Trade(COVERSHORT, price, pos[1] - KeepAmount, pos, PriceTick)}LogStatus(_D())Sleep(1000)}}
策略参数

回测效果




我们致力于人工智能、量化交易领域前沿研究,分享前沿论文、模型代码、策略实现。如有相关需求,请私信与我们联系。
请加微信“LingDuTech163”,或公众号后台私信“联系方式”。
关注【灵度智能】公众号,获取更多AI资讯。