리소스 로딩... 로딩...

디지털 통화 선물 쌍평선 전환점 전략 (교육)

저자:발명가들의 수량화 - 작은 꿈, 2021-12-03 16:50:24, 업데이트: 2023-09-20 10:24:03

img

디지털 통화 선물 쌍평선 전환점 전략 (교육)

이 글은 간단한 트렌드 전략을 설계하는 방법에 대한 설명으로, 전략 설계 차원에서만 설명되어 초보자가 간단한 전략을 설계하는 방법을 배우고 전략 프로그램의 실행 과정을 이해하도록 도와줍니다. 전략의 우수성과 불우성은 전략 파라미터와 크게 관련이 있습니다. (거의 대부분의 트렌드 전략은 이렇게합니다.)

전략 설계

두 개의 EMA 평선 지표를 사용하여, EMA 평선이 모두 굽어지는 경우; 전환점이 오픈, 오픈, 오픈 시그널 (또는 반손) 으로 설계된 고정 목표 수익 격차 평면; 설명은 전략 코드에서 직접 작성되어 쉽게 읽을 수 있습니다. 전략 코드는 전반적으로 매우 간결하며 입문 학습에 적합합니다.

전략 코드

/*backtest
start: 2021-09-01 00:00:00
end: 2021-12-02 00:00:00
period: 1h
basePeriod: 5m
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
*/

// 以上 /**/ 内为回测默认设置,在回测页面可以用回测页面上的相关控件重新设置

var LONG = 1       // 持多头仓位的标记,枚举常量
var SHORT = -1     // 持空头仓位的标记,枚举常量
var IDLE = 0       // 不持仓时的标记,枚举常量

// 获取指定方向的持仓,positions为持仓数据,direction为要获取的持仓方向
function getPosition(positions, direction) {
    var ret = {Price : 0, Amount : 0, Type : ""}    // 定义一个不持仓时的结构
    // 遍历positions,从中找到符合direction方向的持仓
    _.each(positions, function(pos) {
        if (pos.Type == direction) {
            ret = pos
        }
    })
    // 返回找到的持仓
    return ret 
}

// 取消当前交易对、合约的所有挂单
function cancellAll() {
    // 死循环,不停检测,直到触发break跳出
    while (true) {
        // 获取当前交易对、合约的挂单数据,即orders
        var orders = _C(exchange.GetOrders)
        if (orders.length == 0) {
            // 当orders为空数组时,即 orders.length == 0 时,执行break跳出while循环
            break
        } else {
            // 遍历当前所有挂单,逐个取消挂单
            for (var i = 0 ; i < orders.length ; i++) {
                // 具体撤销某个订单的函数,撤销ID为:orders[i].Id的订单
                exchange.CancelOrder(orders[i].Id, orders[i])
                Sleep(500)
            }
        }
        Sleep(500)
    }
}

// 平仓函数,根据传入的交易函数tradeFunc,方向direction,去执行平仓
function cover(tradeFunc, direction) {
    var mapDirection = {"closebuy": PD_LONG, "closesell": PD_SHORT}
    var positions = _C(exchange.GetPosition)  // 获取当前交易对、合约的持仓数据
    var pos = getPosition(positions, mapDirection[direction])  // 找到指定的平仓方向的持仓信息
    // 当持仓量大于0(有仓位才能平仓)
    if (pos.Amount > 0) {
        // 撤销所有可能存在的挂单
        cancellAll()
        // 设置交易方向
        exchange.SetDirection(direction)
        // 执行平仓交易函数
        if (tradeFunc(-1, pos.Amount)) {
            // 下单成功返回 true
            return true 
        } else {
            // 下单失败返回 false 
            return false 
        }
    }
    // 没有仓位返回 true
    return true 
}

// 策略主函数
function main() {
    // 用于切换到OKEX V5模拟盘
    if (okexSimulate) {
        exchange.IO("simulate", true) // 切换到OKEX V5模拟盘测试 
        Log("切换到OKEX V5模拟盘")
    }    
    
    // 设置合约代码,ct为swap 即设置当前操作的合约是永续合约
    exchange.SetContractType(ct)
    // 初始化状态为未持仓
    var state = IDLE
    // 初始化持仓价格为0
    var holdPrice = 0
    // 初始化对比用的时间戳,用于对比当前K线BAR是否变化
    var preTime = 0
    
    // 策略主循环
    while (true) {
        // 获取当前交易对、合约的K线数据
        var r = _C(exchange.GetRecords)
        // 获取K线数据长度,即l
        var l = r.length
        // 判断K线长度 l 必须大于指标周期(不大于指标周期,指标函数无法计算出有效的指标数据),否则重新循环
        if (l < Math.max(ema1Period, ema2Period)) {
            // 等待1000毫秒,即1秒,避免轮转过快
            Sleep(1000)
            // 忽略当前if以后的代码, 重新while循环
            continue
        }
        
        // 计算ema指标数据
        var ema1 = TA.EMA(r, ema1Period)
        var ema2 = TA.EMA(r, ema2Period)
        
        // 画图
        $.PlotRecords(r, 'K线')    // 画K线图
        // 当最后一个BAR时间戳发生变化时,即有新K线BAR产生时
        if(preTime !== r[l - 1].Time){
            // 新BAR出现之前的倒数第一根BAR最后一次更新
            $.PlotLine('ema1', ema1[l - 2], r[l - 2].Time)
            $.PlotLine('ema2', ema2[l - 2], r[l - 2].Time)
            
            // 画新BAR的指标线,即当前倒数第一根BAR上的指标数据
            $.PlotLine('ema1', ema1[l - 1], r[l - 1].Time)
            $.PlotLine('ema2', ema2[l - 1], r[l - 1].Time)
            
            // 更新用于对比的时间戳
            preTime = r[l - 1].Time
        } else {
            // 当没有新BAR产生时,仅仅更新图表上倒数第一根BAR的指标数据
            $.PlotLine('ema1', ema1[l - 1], r[l - 1].Time)
            $.PlotLine('ema2', ema2[l - 1], r[l - 1].Time)
        }
        
        // 开多仓的条件,拐点
        var up = (ema1[l - 2] > ema1[l - 3] && ema1[l - 4] > ema1[l - 3]) && (ema2[l - 2] > ema2[l - 3] && ema2[l - 4] > ema2[l - 3])
        // 开空仓的条件,拐点
        var down = (ema1[l - 2] < ema1[l - 3] && ema1[l - 4] < ema1[l - 3]) && (ema2[l - 2] < ema2[l - 3] && ema2[l - 4] < ema2[l - 3])
        
        // 开多仓的条件触发并且当前持有空头仓位,或者开多仓的条件触发并且没持仓
        if (up && (state == SHORT || state == IDLE)) {
            // 如果持有空头仓位,先平仓
            if (state == SHORT && cover(exchange.Buy, "closesell")) {
                // 平仓后标记未持仓状态
                state = IDLE
                // 重置持仓价格为0
                holdPrice = 0
                // 在图表上标记
                $.PlotFlag(r[l - 1].Time, 'coverShort', 'CS')
            }
            // 平仓后反手开多仓
            exchange.SetDirection("buy")
            if (exchange.Buy(-1, amount)) {
                // 标记当前状态
                state = LONG
                // 记录当前价格
                holdPrice = r[l - 1].Close
                $.PlotFlag(r[l - 1].Time, 'openLong', 'L')
            }
        } else if (down && (state == LONG || state == IDLE)) {
            // 和 up 条件的判断同理
            if (state == LONG && cover(exchange.Sell, "closebuy")) {
                state = IDLE
                holdPrice = 0
                $.PlotFlag(r[l - 1].Time, 'coverLong', 'CL')
            }
            exchange.SetDirection("sell")
            if (exchange.Sell(-1, amount)) {
                state = SHORT
                holdPrice = r[l - 1].Close
                $.PlotFlag(r[l - 1].Time, 'openShort', 'S')
            }
        }
        
        // 止盈
        if (state == LONG && r[l - 1].Close - holdPrice > profitTarget && cover(exchange.Sell, "closebuy")) {            
            state = IDLE
            holdPrice = 0
            $.PlotFlag(r[l - 1].Time, 'coverLong', 'CL')
        } else if (state == SHORT && holdPrice - r[l - 1].Close > profitTarget && cover(exchange.Buy, "closesell")) {            
            state = IDLE
            holdPrice = 0
            $.PlotFlag(r[l - 1].Time, 'coverShort', 'CS')
        }
        // 在状态栏上显示时间
        LogStatus(_D())
        Sleep(500)        
    }
}

img

img

이 전략의 소스 코드는:https://www.fmz.com/strategy/333269

이 전략은 단순히 프로그래밍을 가르치는 것입니다.


관련

더 많은

꿈은 8자리입니다.1H 또는 4H? 아니면 어떤 시간일까요?

가벼운 구름감사합니다.

발명가들의 수량화 - 작은 꿈K선 주기가 얼마나 큰지 설정하고 계산된 평균선은 시간 주기의 평균선이 얼마나 큰지 설명합니다.