JavaScript-Version der SuperTrend-Richtlinie

Schriftsteller:Kleine Träume, Erstellt: 2020-04-17 16:36:24, Aktualisiert: 2023-10-09 22:46:56

img

JavaScript-Version der SuperTrend-Richtlinie

Der SuperTrend-Indikator auf dem TV gibt verschiedene Versionen. Ich suchte nach einem einfachen Algorithmus, um es zu verstehen. Ich fand einen kleinen Unterschied zwischen den SuperTrend-Indikatoren, die auf dem TV-Chart des Erfinders auf der Quantitative Trading Platform Retesting System geladen wurden.

SuperTrend-Anzeiger JavaScript-Versionsalgorithmen

// 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]
}

// 测试指标用的main函数,并非交易策略
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)
    }
}

Test-Code-Retest-Vergleiche:img

img

Eine einfache Strategie mit dem SuperTrend

Der einfache Teil der Handelslogik besteht darin, mehr zu machen, wenn sich ein Leerhandelstrend in einen Mehrhandelstrend verwandelt. Einer der wichtigsten Faktoren ist die Tatsache, dass die meisten Positionen in einem langfristigen Trend verwandelt werden.

Strategieparameter:img

SuperTrend-Handelsstrategien

/*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"}]
*/

// 全局变量
var OpenAmount = 0                                                  // 开仓后持仓的数量
var KeepAmount = 0                                                  // 保留仓位
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

// 交易逻辑部分
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){    // 处理交易
    if(Type == OPENLONG || Type == OPENSHORT){              // 处理开仓
        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){     // 处理平仓
        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){                          // 开多仓
            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 = SHORT
                continue
            }
            price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
            Trade(OPENSHORT, price, Amount - pos[1], pos, PriceTick)
        }

        if(State == COVERLONG){                                         // 处理平多仓
            pos = GetPosition(PD_LONG)                                  // 获取持仓信息
            if(pos[1] == 0){                                            // 判断持仓是否为 0
                $.PlotFlag(currBar.Time, "平多仓", '----CL')             // 标记
                State = IDLE
                continue
            }
            price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
            Trade(COVERLONG, price, pos[1], pos, PriceTick)
        }
    
        if(State == COVERSHORT){                                        // 处理做多仓
            pos = GetPosition(PD_SHORT)
            if(pos[1] == 0){
                $.PlotFlag(currBar.Time, "平空仓", '----CS')
                State = IDLE
                continue
            }
            price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2
            Trade(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 * 2
            Trade(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 : SHORT
                continue
            }
            price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2
            Trade(COVERSHORT, price, pos[1] - KeepAmount, pos, PriceTick)
        }

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

Die Strategie ist unter:https://www.fmz.com/strategy/201837

Wiederholung der Ergebnisse

Parameter-Einstellung, K-Linie-Zyklus, Referenz: Homily der GroßenSuperTrend V.1 - Super Trendlinie-SystemDie K-Linie-Zyklen sind auf 15 Minuten gesetzt, die SuperTrend-Parameter auf 45,3. Zurückschauen der OKEX-Futuresquarter-Kontrakte auf die Zeit des letzten Jahres, ein Kontrakt pro Handel gesetzt, da die Kapitalverwertung niedrig ist, da nur ein Kontrakt pro Handel gesetzt wird.

img

Die Strategie ist nur zum Lernen, aber sie ist vorsichtig.


Verwandt

Mehr

1070278998@qq.comWas bedeutet Return (up, down), wie sieht der zurückgegebene Inhalt aus, ist der Supertrend nicht auch eine Zahl?

SkyfffireDie Träume sind hartnäckig.

ViolainDer Unterschied zum Fernseher ist, dass es sich bei der ATR-Rechnung um ein Problem handelt, das in FMZ-Packs enthalten sein sollte, z. B. dass die Eingabe-Zyklen 7 sind, und dass die ersten 6 Werte von ATR, die berechnet wurden, Null sein sollten, aber in Wirklichkeit nicht.

Kleine Träume$.PlotLine ist eine Schnittstellenfunktion für die Zeichnungszeilen-Klassenbank, die in der Regel in der Strategie Square kopiert werden kann.

1070278998@qq.com$2. 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) Was bedeutet der Code hinter dem L, wenn es sich um eine Unterlinie handelt, und muss das r hinter dem Code mit ihm verwendet werden, um die Zeit, in der das L erscheint, zu bezeichnen?

1070278998@qq.com$2. 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) Was bedeutet der Code hinter dem L, wenn es eine Unterlinie ist, und ob ein r hinter dem Code mit ihm verbunden sein muss?

Kleine TräumeWas für ein Sp?

Kleine Träumeup[up.length - 1], das erste Datum der Negativzahl des Indikators, das dem ersten Negativwert der K-Linie BAR entspricht.

1070278998@qq.comWie definiert man die Periode von sp, welche Parameter müssen geändert werden?

1070278998@qq.com Up.length-1就是上边线最近的一个数字吗

Kleine TräumeDie Rückgabe ist eine zweidimensionale Array, die oben die Linie ist und unten die Linie. Die Rückgabe ist die gesamte Indikatordaten.

Kleine TräumeDie Algorithmen in der Tradingview werden im Folgenden näher untersucht.

ViolainJa, ich habe das Problem identifiziert, es ist ein bisschen verwirrt, ich weiß nicht, mit welchem.

Kleine TräumeOkay, danke, danke, aber ich benutze ATR aus der Talib-Bibliothek, und die Berechnung scheint nicht richtig zu sein, und die Daten, die durch die direkte Umsetzung von ATR durch die Algorithmen ergeben werden, sind auch ein wenig unterschiedlich.