另类交易思路--K线面积交易策略

Author: 发明者量化-小小梦, Created: 2023-11-03 17:12:42, Updated: 2023-11-03 17:35:03

img

看着一个不怎么靠谱的交易想法–K线面积交易策略,本文我们一起探讨这个思路以及尝试实现这个脚本。

K线面积策略的主要思想

K线面积策略是一种基于价格K线与均线之间的面积关系的交易策略。它的主要思想是通过分析价格趋势的幅度和变化,以及买卖情绪的转换,来预测股市价格的可能走势,从而决定开仓和出场时机。这个策略依赖于K线与均线之间的面积,以及KDJ指标的数值,来生成多头和空头交易信号。

K线面积策略的原理

K线面积是指价格K线与均线之间的空间面积,通过将每根Bar的收盘价减去均线值,然后求和来计算。当价格上涨趋势幅度大、时间长时,K线面积会变大,而在震荡市或震荡后反转时,K线面积较小。根据“物极必反”的原理,上涨趋势越大,时间越长,对应的K线面积越大,反转的概率越大,就像弹簧一样,拉得越长,反弹力度越大。因此,设定一个K线面积的阈值,当达到该阈值时,价格趋势可能走完,反转的可能性较大。

为了进一步确认趋势即将反转,引入KDJ指标,用于判断买卖情绪的转换。这个策略的阈值和KDJ指标值的设定可以根据具体情况和需求进行调整,以增强策略的准确性。

K线面积策略的优势

K线面积策略的优势在于它结合了价格趋势的幅度和变化,以及买卖情绪的转换,提供了相对完整的量化交易策略。其优势包括:

  • 提供了简单而直观的方法来识别趋势反转的可能性,帮助交易者更好地掌握市场走势。
  • 利用K线面积和KDJ指标的结合,增加了策略的可靠性和精确性。
  • 灵活性高,可以根据市场情况进行参数的调整,以满足不同的交易需求。

K线面积策略的风险

尽管K线面积策略具有一定的优势,但它也存在一些风险,包括:

  • 阈值的设置可能需要一些经验和调整,如果设置不当,可能导致误判市场走势。
  • KDJ指标的准确性受市场波动和噪音的影响,可能出现虚假信号。
  • 策略的表现可能在不同市场条件下变化,需要不断优化和调整。

K线面积策略的优化方向

为了优化K线面积策略,可以考虑以下方向:

  • 参数优化:不断调整和优化阈值和KDJ指标的参数,以适应不同市场情况和交易需求。
  • 风险管理:实施有效的风险管理策略,包括止损和止盈规则,以降低损失风险。
  • 多策略组合:将K线面积策略与其他策略相结合,以提高综合交易策略的表现。
  • 实时监测和调整:定期监测策略的表现,根据实际情况进行调整和改进。

使用JavaScript语言实现这个策略

  • 计算K线面积

  • 多头开仓信号:

    (1)下降趋势的“K线面积”达到阈值,之前成立即可

    (2)KDJ指标值大于80

  • 空头开仓信号:

    (1)上涨趋势的“K线面积”达到阈值,之前成立即可

    (2)KDJ指标值小于20

  • 多头/空头出场:ATR跟踪止损止盈

代码实现

// 参数
var maPeriod = 30
var threshold = 50000
var amount = 0.1

// 全局变量
let c = KLineChart({})
let openPrice = 0
let tradeState = "NULL"  // NULL BUY SELL

function calculateKLineArea(r, ma) {
    var lastCrossUpIndex = null
    var lastCrossDownIndex = null
    for (var i = r.length - 1 ; i >= 0 ; i--) {
        if (ma[i] !== null && r[i].Open < ma[i] && r[i].Close > ma[i]) {
            lastCrossUpIndex = i
            break
        } else if (ma[i] !== null && r[i].Open > ma[i] && r[i].Close < ma[i]) {
            lastCrossDownIndex = i
            break
        }

        if (i >= 1 && ma[i] !== null && ma[i - 1] !== null && r[i - 1].Close < ma[i - 1] && r[i].Close > ma[i]) {
            lastCrossUpIndex = i
            break
        } else if (i >= 1 && ma[i] !== null && ma[i - 1] !== null && r[i - 1].Close > ma[i - 1] && r[i].Close < ma[i]) {
            lastCrossDownIndex = i
            break
        }
    }

    var area = 0
    if (lastCrossDownIndex !== null) {
        for (var i = r.length - 1 ; i >= lastCrossDownIndex ; i--) {
            area -= Math.abs(r[i].Close - ma[i])
        }
    } else if (lastCrossUpIndex !== null) {
        for (var i = r.length - 1 ; i >= lastCrossUpIndex ; i--) {
            area += Math.abs(r[i].Close - ma[i])
        }
    }

    return [area, lastCrossUpIndex, lastCrossDownIndex]
}

function onTick() {
    var r = _C(exchange.GetRecords)
    if (r.length < maPeriod) {
        LogStatus(_D(), "K线数量不足")
        return 
    }
    var ma = TA.MA(r, maPeriod)
    var atr = TA.ATR(r)
    var kdj = TA.KDJ(r)
    var lineK = kdj[0]
    var lineD = kdj[1]
    var lineJ = kdj[2]
    var areaInfo = calculateKLineArea(r, ma)
    var area = _N(areaInfo[0], 0)
    var lastCrossUpIndex = areaInfo[1]
    var lastCrossDownIndex = areaInfo[2]
    
    r.forEach(function(bar, index) {
        c.begin(bar)
        c.plotcandle(bar.Open, bar.High, bar.Low, bar.Close, {overlay: true})
        let maLine = c.plot(ma[index], "ma", {overlay: true})
        let close = c.plot(bar.Close, 'close', {overlay: true})
        c.fill(maLine, close, {color: bar.Close > ma[index] ? 'rgba(255, 0, 0, 0.1)' : 'rgba(0, 255, 0, 0.1)'})
        if (lastCrossUpIndex !== null) {
            c.plotchar(bar.Time, {char: '$:' + area, overlay: true})
        } else if (lastCrossDownIndex !== null) {
            c.plotchar(bar.Time, {char: '$:' + area, overlay: true})
        }
        c.plot(lineK[index], "K")
        c.plot(lineD[index], "D")
        c.plot(lineJ[index], "J")

        c.close()
    })
    
    if (tradeState == "NULL" && area < -threshold && lineK[lineK.length - 1] > 70) {
        // long
        let tradeInfo = $.Buy(amount)
        if (tradeInfo) {
            openPrice = tradeInfo.price
            tradeState = "BUY"
        }
    } else if (tradeState == "NULL" && area > threshold && lineK[lineK.length - 1] < 30) {
        // short
        let tradeInfo = $.Sell(amount)
        if (tradeInfo) {
            openPrice = tradeInfo.price
            tradeState = "SELL"
        }
    }
    
    let stopBase = tradeState == "BUY" ? Math.max(openPrice, r[r.length - 2].Close) : Math.min(openPrice, r[r.length - 2].Close)
    if (tradeState == "BUY" && r[r.length - 1].Close < stopBase - atr[atr.length - 2]) {
        // cover long
        let tradeInfo = $.Sell(amount)
        if (tradeInfo) {
            tradeState = "NULL"
            openPrice = 0
        }        
    } else if (tradeState == "SELL" && r[r.length - 1].Close > stopBase + atr[atr.length - 2]) {
        // cover short 
        let tradeInfo = $.Buy(amount)
        if (tradeInfo) {
            tradeState = "NULL"
            openPrice = 0
        }        
    }

    LogStatus(_D(), "area:", area, ", lineK[lineK.length - 2]:", lineK[lineK.length - 2])
}


function main() {    
    if (exchange.GetName().includes("_Futures")) {
        throw "not support Futures"
    }
    while (true) {
        onTick()
        Sleep(1000)
    }
}

策略逻辑十分简单:

1、首先,定义了一些全局变量和参数,包括:

策略参数

  • maPeriod:移动平均的周期。
  • threshold:用于判断买入或卖出时机的阈值。
  • amount:每次交易的数量。

全局变量

  • c:K线图表对象,用于绘制图表。
  • openPrice:记录开仓价格。
  • tradeState:记录交易状态,可以是"NULL"(空仓)、“BUY”(买入)或"SELL"(卖出)。

计算函数

  • calculateKLineArea 函数:这个函数用于计算K线图表上某段时间内价格与移动平均线之间的面积,并返回面积值、最后一次交叉上穿的K线索引和最后一次交叉下穿的K线索引。这些值在后续决策中用于判断买入和卖出时机。

主循环函数

  • onTick 函数:这是主要的策略执行函数,以下是函数内的操作:

    a. 获取最新的K线数据,并确保K线数量不小于 maPeriod,否则记录状态并返回。

    b. 计算移动平均线 ma 和 ATR 指标 atr,以及 KDJ 指标。

    c. 从 areaInfo 中获取面积信息、最后一次交叉上穿的K线索引和最后一次交叉下穿的K线索引。

    d. 使用 K线图表对象 c 绘制K线和指标线,同时根据价格与移动平均线的关系填充不同的颜色。

    e. 根据条件判断买入和卖出的时机:

    如果 tradeState 为 “NULL”,并且面积小于 -threshold 并且 KDJ 的K线值大于70,执行买入操作。 如果 tradeState 为 “NULL”,并且面积大于 threshold 并且 KDJ 的K线值小于30,执行卖出操作。 f. 设置止损和止盈条件,如果达到条件则平仓:

    如果是买入状态,当价格低于上一次交易日的收盘价减去前一日的ATR时,平仓。 如果是卖出状态,当价格高于上一次交易日的收盘价加上前一日的ATR时,平仓。 main 函数:这是主要的执行入口,检查交易所名称是否包含 “_Futures”,如果包含则抛出异常,否则进入一个无限循环,在每次循环中执行 onTick 函数并休眠1秒。

总体来说,这个策略主要依赖于K线图表和技术指标来进行买卖决策,同时采用了止损和止盈的策略来管理风险。请注意,这只是一个示例策略,实际使用时需要根据市场情况和具体需求进行调整和优化。

在FMZ.COM上使用JavaScript语言没有用多少行代码,很简单的就实现了这个模型。并且使用KLineChart函数很容易实现了K线面积的图形表示。策略设计用于加密货币现货市场,使用了「数字货币现货交易类库」模板,使用模板封装的函数下单,也是非常简单易用、易懂。

策略回测

img

img

随便选择了一个回测时间段,虽然没有亏钱但是也没有持续累计住盈利,回撤问题还是比较大。对于这个策略应该还有其它优化方向和空间。有兴趣的可以尝试升级这个策略。

img

通过这个策略我们除了学习到了一个比较另类的交易思路,还学习到了如何画图;表示K线和均线围成的面积;画KDJ指标等。

总结

K线面积策略是一种基于价格趋势幅度和KDJ指标的交易策略,它通过分析K线与均线之间的面积和买卖情绪的转换,帮助交易者预测市场走势。尽管存在一定的风险,但通过不断优化和调整,这个策略可以提供有力的交易工具,帮助交易者更好地应对市场波动。重要的是,交易者应根据具体情况和市场条件,灵活地调整策略的参数和规则,以实现更好的交易绩效。


More