JavaScript-Version der SuperTrend-Strategie

Schriftsteller:Gutes, Erstellt: 2020-04-29 12:09:15, aktualisiert: 2023-11-06 20:03:58

img

JavaScript-Version der SuperTrend-Strategie

Es gibt viele Versionen des SuperTrend-Indikators auf dem Fernseher. Ich fand einen relativ leicht verständlichen Algorithmus und transplantierte ihn. Verglichen mit dem SuperTrend-Indikator, der auf dem TV-Chart der FMZ-Handelsplattform-Backtest-System geladen ist, fand ich einen leichten Unterschied und verstand nicht den Grund für die Ursachen, ich freue mich auf die Anleitung unserer Leser. Ich werde zuerst mein Verständnis wie folgt zeigen.

SuperTrend-Indikator JavaScript-Versionsalgorithmus

// VIA: https://github.com/freqtrade/freqtrade-strategies/issues/30

function SuperTrend(r, period, multiplier) {
    // atr
    var atr = talib.ATR(r, period)

    // baseUp , baseDown
    var 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 , fiDown
    var fiUp = []
    var fiDown = []
    var prevFiUp = 0
    var prevFiDown = 0
    for (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 = NaN
    for (var i = 0; i < r.length; i++) {
        if (i < period) {
            st.push(NaN)
            continue
        }

        var nowSt = 0
        if (((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]
}

// The main function for testing indicators is not a trading strategy
function main() {
    while (1) {
        var r = _C(exchange.GetRecords)
        var st = SuperTrend(r, 10, 3)

        $.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)

        Sleep(2000)
    }
}

Testcode-Backtest-Vergleich:

img img

Eine einfache Strategie mit dem SuperTrend-Indikator

Der Teil der Handelslogik ist relativ einfach, d.h. wenn sich der kurze Trend in einen langen Trend verwandelt, werden lange Positionen eröffnet. Öffnen Sie eine Short-Position, wenn sich der lange Trend in einen Short-Trend verwandelt.

Strategieparameter:

img

SuperTrend-Handelsstrategie

/*backtest
start: 2019-08-01 00:00:00
end: 2020-03-11 00:00:00
period: 15m
basePeriod: 5m
exchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD"}]
*/

// Global variables
var OpenAmount = 0                                                  // The number of open positions after opening
var KeepAmount = 0                                                  // Reserved position
var IDLE = 0
var LONG = 1
var SHORT = 2
var COVERLONG = 3
var COVERSHORT = 4
var COVERLONG_PART = 5
var COVERSHORT_PART = 6
var OPENLONG = 7
var OPENSHORT = 8

var State = IDLE

// Trading logic part
function GetPosition(posType) {
    var positions = _C(exchange.GetPosition)
    /*
    if(positions.length > 1){
        throw "positions error:" + JSON.stringify(positions)
    }
    */
    var count = 0
    for(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){    // Processing transactions
    if(Type == OPENLONG || Type == OPENSHORT){              // Handling open positions
        exchange.SetDirection(Type == OPENLONG ? "buy" : "sell")
        var pfnOpen = Type == OPENLONG ? exchange.Buy : exchange.Sell
        var idOpen = pfnOpen(Price, Amount, CurrPos, OnePriceTick, Type)
        Sleep(TradeInterval)
        if(idOpen) {
            exchange.CancelOrder(idOpen)
        } else {
            CancelPendingOrders()
        }
    } else if(Type == COVERLONG || Type == COVERSHORT){     // Deal with closing positions
        exchange.SetDirection(Type == COVERLONG ? "closebuy" : "closesell")
        var pfnCover = Type == COVERLONG ? exchange.Sell : exchange.Buy
        var 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) {
    // atr
    var atr = talib.ATR(r, period)

    // baseUp , baseDown
    var 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 , fiDown
    var fiUp = []
    var fiDown = []
    var prevFiUp = 0
    var prevFiDown = 0
    for (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 = NaN
    for (var i = 0; i < r.length; i++) {
        if (i < period) {
            st.push(NaN)
            continue
        }

        var nowSt = 0
        if (((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 = 0
function 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 = null
        var price = null
        if(State == OPENLONG){                          // Open long positions
            pos = GetPosition(PD_LONG)                  // Check positions
                                                        // Determine whether the status is satisfied, if it is satisfied, modify the status
            if(pos[1] >= Amount){                       // Open positions exceed or equal to the open positions set by the parameters
                Sleep(1000)
                $.PlotFlag(currBar.Time, "Open long positions", 'OL') // mark
                
                OpenAmount = pos[1]                     // Record the number of open positions
                State = LONG                            // Mark as long
                continue
            }
            price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2     // Calculate the price
            Trade(OPENLONG, price, Amount - pos[1], pos, PriceTick)                 // Placing Order function (Type, Price, Amount, CurrPos, PriceTick)
        }

        if(State == OPENSHORT){                         // Open short position
            pos = GetPosition(PD_SHORT)                 // Check positions
            if(pos[1] >= Amount){
                Sleep(1000)
                $.PlotFlag(currBar.Time, "Open short position", 'OS')
                
                OpenAmount = pos[1]
                State = SHORT
                continue
            }
            price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
            Trade(OPENSHORT, price, Amount - pos[1], pos, PriceTick)
        }

        if(State == COVERLONG){                                         // Handling long positions
            pos = GetPosition(PD_LONG)                                  // Get position information
            if(pos[1] == 0){                                            // Determine if the position is 0
                $.PlotFlag(currBar.Time, "Close long position", '----CL')             // mark
                State = IDLE
                continue
            }
            price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
            Trade(COVERLONG, price, pos[1], pos, PriceTick)
        }
    
        if(State == COVERSHORT){                                        // Deal with long positions
            pos = GetPosition(PD_SHORT)
            if(pos[1] == 0){
                $.PlotFlag(currBar.Time, "Close short position", '----CS')
                State = IDLE
                continue
            }
            price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2
            Trade(COVERSHORT, price, pos[1], pos, PriceTick)
        }

        if(State == COVERLONG_PART) {                                   // Partially close long positions
            pos = GetPosition(PD_LONG)                                  // Get positions
            if(pos[1] <= KeepAmount){                                   // The position is less than or equal to the holding amount, this time the closing action is completed
                $.PlotFlag(currBar.Time, "Close long positions, keep:" + KeepAmount, '----CL')     // mark
                State = pos[1] == 0 ? IDLE : LONG                                  // update status
                continue
            }
            price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
            Trade(COVERLONG, price, pos[1] - KeepAmount, pos, PriceTick)
        }

        if(State == COVERSHORT_PART){
            pos = GetPosition(PD_SHORT)
            if(pos[1] <= KeepAmount){
                $.PlotFlag(currBar.Time, "Close short positions, keep:" + KeepAmount, '----CS')
                State = pos[1] == 0 ? IDLE : SHORT
                continue
            }
            price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2
            Trade(COVERSHORT, price, pos[1] - KeepAmount, pos, PriceTick)
        }

        LogStatus(_D())
        Sleep(1000)
    }
}

Strategieadresse:https://www.fmz.com/strategy/201837

Leistung bei Rückversuchen

Einstellung der Parameter, K-Linienperiode, Referenz: Predigt SuperTrend V.1Super-Trend-Liniensystem

Der K-Linienzeitraum wird auf 15 Minuten und der SuperTrend-Parameter auf 45, 3 eingestellt.

img


Verwandt

Mehr