Стратегия SuperTrend версии JavaScript

Автор:Маленькие мечты, Создано: 2020-04-17 16:36:24, Обновлено: 2023-10-09 22:46:56

img

Стратегия SuperTrend версии JavaScript

СуперТренд на ТВ существует в нескольких версиях, ищет более понятный алгоритм, который переносится, и сравнивает его с индексом SuperTrend, загруженным на графике TV, и обнаруживает небольшие различия.

Алгоритм версии SuperTrend Indicator JavaScript

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

Проверка кода для сравнения:img

img

Простая стратегия с помощью индикаторов SuperTrend

Логическая часть торговли, более простая, заключается в том, чтобы открыть больше позиций, когда тренд на пустом месте превращается в тренд на многочисленном месте. Если многообещающий тренд превратится в пустой, то можно открыть пустую позицию.

Параметры стратегии:img

Стратегия торговли Super Trend

/*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)
    }
}

Политический адрес:https://www.fmz.com/strategy/201837

Проверка результатов

Параметры настройки, цикл K-линии, ссылки: homilySuperTrend V.1 - система сверхтенденционных линийК-линейный цикл установлен на 15 минут, параметры SuperTrend установлен на 45,3; обратный анализ времени OKEX Futures Quarter контракта за последний год, установленный на один контракт за одну сделку, так как установлен только один контракт за одну сделку, так что использование средств очень низкое, не обращая внимания на значение Sharp.

img

С помощью этой стратегии можно научиться, но с осторожностью.


Связанные

Больше

1070278998@qq.comЧто означает алгоритм return ((up, down), как выглядит возвращаемое содержимое, не является ли супертенденция также числом, если вы хотите использовать эту функцию, нет.

СкайффайрМечта - это дерзость.

ВиолинаВ отличие от телевизора, в котором должна быть проблема с вычислением ATR в упаковке fmz, например, цикл ввода 7, вычисляется, что первые 6 значений ATR должны быть нулевыми, но на самом деле это не так.

Маленькие мечты$.PlotLine - это интерфейсная функция для библиотеки линий рисунка, в частности, можно скопировать эту модель в библиотеке линий рисунка в Policy Square.

1070278998@qq.com$.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) Что означает код после L, и если это низкая линия, нужно ли использовать r после нее, чтобы обозначить время появления L?

1070278998@qq.com$.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) Что означает код после L, если это низкая линия, и нужно ли использовать r вместе с ней?

Маленькие мечтыЧто за "сп"?

Маленькие мечтыup[up.length - 1], первое число дефиците показателя, соответствующее первому дефиците линии K BAR.

1070278998@qq.comКак определить цикл sp, какие параметры нужно изменить?

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

Маленькие мечтыВозвращается двумерная матрица, в которой up - это линия выше, а down - линия ниже. Возвращается весь показатель данных.

Маленькие мечтыНу, давайте рассмотрим алгоритмы в Tradingview подробнее.

ВиолинаДа, да, да, да, да, да, да, да, да, да, да, да, да, да, да, да, да, да, да, да, да.

Маленькие мечтыХорошо, спасибо, спасибо, но я использую ATR из библиотеки Talib, и вычисления не совсем верны, и данные, полученные при непосредственном использовании алгоритма ATR, также немного отличаются.