Les ressources ont été chargées... Je charge...

Stratégie ATR multi-espèces de contrats à terme sur devises numériques (tutoriel)

Auteur:FMZ~Lydia, Créé: 2022-11-08 10:34:22, Mis à jour: 2023-09-15 20:55:33

img

Récemment, certains utilisateurs de notre plateforme sont impatients de transplanter une stratégie MyLanguage dans une stratégie JavaScript, ce qui peut ajouter de nombreuses idées d'optimisation de manière flexible. Même étendre la stratégie à des versions multi-espèces. Parce que la stratégie MyLanguage est généralement une stratégie de tendance, et beaucoup d'entre elles sont exécutées sur la base du modèle de prix de clôture. L'interface API de l'échange de requêtes de stratégie n'est pas très fréquente, ce qui convient à la transplantation vers une version de stratégie multi-espèces. Dans cet article, nous prendrons une stratégie MyLanguage simple comme exemple pour la transplanter dans une version simple du langage JavaScript. Le but principal est d'enseigner et de soutenir la recherche.

La stratégie de MyLanguage à transplanter

TR:=MAX(MAX((H-L),ABS(REF(C,1)-H)),ABS(REF(C,1)-L));
ATR:=EMA(TR,LENGTH2);

MIDLINE^^EMA((H + L + C)/3,LENGTH1);
UPBAND^^MIDLINE + N*ATR;
DOWNBAND^^MIDLINE - N*ATR;


BKVOL=0 AND C>=UPBAND AND REF(C,1)<REF(UPBAND,1),BPK;
SKVOL=0 AND C<=DOWNBAND AND REF(C,1)>REF(DOWNBAND,1),SPK;

BKVOL>0 AND C<=MIDLINE,SP(BKVOL);
SKVOL>0 AND C>=MIDLINE,BP(SKVOL);
// stop loss
// stop loss
C>=SKPRICE*(1+SLOSS*0.01),BP;
C<=BKPRICE*(1-SLOSS*0.01),SP;
AUTOFILTER;

La logique de négociation de cette stratégie est simple. Tout d'abord, calculez l'ATR en fonction des paramètres, puis calculez la moyenne des prix les plus élevés, les plus bas et de clôture de tous les BAR de la ligne K, puis calculez l'indicateur EMA en fonction des données moyennes. Enfin, combinez l'ATR et le coefficient N dans les paramètres pour calculer la upBand et la downBand.

Les positions d'ouverture et de vente sont basées sur le prix de clôture. Ouvrez des positions longues lorsqu'il dépasse le upBand et vendez la position d'ouverture (lorsque vous détenez des positions courtes). Ouvrez des positions courtes lorsqu'il dépasse le downBand et vendez la position d'ouverture. Lorsque le prix de clôture atteint la ligne médiane, la position est fermée et lorsque le prix de clôture atteint le prix de stop loss, la position est également fermée (selon le SLOSS, le stop loss est de 1, c'est-à-dire de 0,01, c'est-à-dire de 1%). La stratégie est exécutée selon un modèle de prix de clôture.

OK, si nous comprenons les exigences stratégiques et les idées de MyLanguage, nous pouvons commencer à les transplanter.

Prototype de stratégie de transplantation et de conception

Pour faciliter l'apprentissage des idées d'écriture de stratégie, les commentaires sont écrits directement dans le code de stratégie.

// parse params parameters, and parse strings as objects
var arrParam = JSON.parse(params)

// this function creates a chart configuration
function createChartConfig(symbol, atrPeriod, emaPeriod, index) {   // symbol : trading pair, atrPeriod : ATR parameter period , emaPeriod : EMA parameter period, exchange object index corresponding to index
    var chart = {                                        
        __isStock: true,    
        extension: {
                layout: 'single', 
                height: 600, 
        },
        title : { text : symbol},                       
        xAxis: { type: 'datetime'},           
        series : [                                          
            {                                      
                type: 'candlestick',    // K-line data series                         
                name: symbol,   
                id: symbol + "-" + index,
                data: []                                           
            }, {                                      
                type: 'line',           // EMA
                name: symbol + ',EMA:' + emaPeriod,          
                data: [],               
            }, {
                type: 'line',           // upBand
                name: symbol + ',upBand' + atrPeriod,
                data: []
            }, {
                type: 'line',           // downBand
                name: symbol + ',downBand' + atrPeriod,
                data: []
            }, {
                type: 'flags',
                onSeries: symbol + "-" + index,
                data: [],
            }
        ]
    }
    return chart
}

// main Logic
function process(e, kIndex, c) {    // e is the exchange object, exchanges [0]..., kIndex is the K-line data series in the chart, and c is the chart object
    // obtain K-line data
    var r = e.GetRecords(e.param.period)
    if (!r || r.length < e.param.atrPeriod + 2 || r.length < e.param.emaPeriod + 2) {
        // if the K-line data length is insufficient, return
        return 
    }

    // calculate ATR indicators
    var atr = TA.ATR(r, e.param.atrPeriod)
    var arrAvgPrice = []
    _.each(r, function(bar) {
        arrAvgPrice.push((bar.High + bar.Low + bar.Close) / 3)
    })
    // calculate EMA indicators
    var midLine = TA.EMA(arrAvgPrice, e.param.emaPeriod)
    // calculate upBand and downBand
    var upBand = []
    var downBand = [] 
    _.each(midLine, function(mid, index) {
        if (index < e.param.emaPeriod - 1 || index < e.param.atrPeriod - 1) {
            upBand.push(NaN)
            downBand.push(NaN)
            return 
        }
        upBand.push(mid + e.param.trackRatio * atr[index])
        downBand.push(mid - e.param.trackRatio * atr[index])
    })

    // draw the chart
    for (var i = 0 ; i < r.length ; i++) {
        if (r[i].Time == e.state.lastBarTime) {
            // update
            c.add(kIndex, [r[i].Time, r[i].Open, r[i].High, r[i].Low, r[i].Close], -1)
            c.add(kIndex + 1, [r[i].Time, midLine[i]], -1)
            c.add(kIndex + 2, [r[i].Time, upBand[i]], -1)
            c.add(kIndex + 3, [r[i].Time, downBand[i]], -1)
        } else if (r[i].Time > e.state.lastBarTime) {
            // add
            e.state.lastBarTime = r[i].Time
            c.add(kIndex, [r[i].Time, r[i].Open, r[i].High, r[i].Low, r[i].Close])  
            c.add(kIndex + 1, [r[i].Time, midLine[i]])
            c.add(kIndex + 2, [r[i].Time, upBand[i]])
            c.add(kIndex + 3, [r[i].Time, downBand[i]])
        }
    }

    // check the position
    var pos = e.GetPosition()
    if (!pos) {
        return 
    }
    var holdAmount = 0
    var holdPrice = 0
    if (pos.length > 1) {
        throw "long and short positions are checked at the same time!"
    } else if (pos.length != 0) {
        holdAmount = pos[0].Type == PD_LONG ? pos[0].Amount : -pos[0].Amount
        holdPrice = pos[0].Price
    }

    if (e.state.preBar == -1) {
        e.state.preBar = r[r.length - 1].Time
    }
    // check the signal
    if (e.state.preBar != r[r.length - 1].Time) {   // closing price model
        if (holdAmount <= 0 && r[r.length - 3].Close < upBand[upBand.length - 3] && r[r.length - 2].Close > upBand[upBand.length - 2]) {   // the closing price cross over the upBand
            if (holdAmount < 0) {   // hold a short positions, close them
                Log(e.GetCurrency(), "close short positions", "#FF0000")
                $.CoverShort(e, e.param.symbol, Math.abs(holdAmount))
                c.add(kIndex + 4, {x: r[r.length - 2].Time, color: 'red', shape: 'flag', title: 'close', text: "close short positions"})
            }
            // open long positions
            Log(e.GetCurrency(), "open long positions", "#FF0000")
            $.OpenLong(e, e.param.symbol, 10)
            c.add(kIndex + 4, {x: r[r.length - 2].Time, color: 'red', shape: 'flag', title: 'long', text: "open long positions"})
        } else if (holdAmount >= 0 && r[r.length - 3].Close > downBand[downBand.length - 3] && r[r.length - 2].Close < downBand[downBand.length - 2]) {  // the closing price cross down the downBand
            if (holdAmount > 0) {   // hold long positions, close them
                Log(e.GetCurrency(), "close long positions", "#FF0000")
                $.CoverLong(e, e.param.symbol, Math.abs(holdAmount))
                c.add(kIndex + 4, {x: r[r.length - 2].Time, color: 'green', shape: 'flag', title: 'close', text: "close long positions"})
            }
            // open short positions
            Log(e.GetCurrency(), "open short positions", "#FF0000")
            $.OpenShort(e, e.param.symbol, 10)
            c.add(kIndex + 4, {x: r[r.length - 2].Time, color: 'green', shape: 'flag', title: 'short', text: "open short positions"})
        } else {
            // close positions
            if (holdAmount > 0 && (r[r.length - 2].Close <= holdPrice * (1 - e.param.stopLoss) || r[r.length - 2].Close <= midLine[midLine.length - 2])) {   // Hold a long position, the closing price is less than or equal to the midline, stop loss at the opening price
                Log(e.GetCurrency(), "trigger midline or stop loss, close long positions", "#FF0000")
                $.CoverLong(e, e.param.symbol, Math.abs(holdAmount))
                c.add(kIndex + 4, {x: r[r.length - 2].Time, color: 'green', shape: 'flag', title: 'close', text: "close long positions"})
            } else if (holdAmount < 0 && (r[r.length - 2].Close >= holdPrice * (1 + e.param.stopLoss) || r[r.length - 2].Close >= midLine[midLine.length - 2])) {  // Hold a short position, the closing price is greater than or equal to the midline, stop loss at the opening price
                Log(e.GetCurrency(), "trigger midline or stop loss, close short positions", "#FF0000")
                $.CoverShort(e, e.param.symbol, Math.abs(holdAmount))
                c.add(kIndex + 4, {x: r[r.length - 2].Time, color: 'red', shape: 'flag', title: 'close', text: "close short positions"})
            }
        }
        e.state.preBar = r[r.length - 1].Time
    }
}

function main() {
    var arrChartConfig = []
    if (arrParam.length != exchanges.length) {
        throw "Parameters and exchange objects do not match!"
    }
    var arrState = _G("arrState")
    _.each(exchanges, function(e, index) {
        if (e.GetName() != "Futures_Binance") {
            throw "The exchange is not supported!"
        }
        e.param = arrParam[index]
        e.state = {lastBarTime: 0, symbol: e.param.symbol, currency: e.GetCurrency()}
        if (arrState) {
            if (arrState[index].symbol == e.param.symbol && arrState[index].currency == e.GetCurrency()) {
                Log("restore:", e.state)
                e.state = arrState[index]
            } else {
                throw "The restored data does not match the current settings!"
            }
        }
        e.state.preBar = -1   // initial setting -1
        e.SetContractType(e.param.symbol)
        Log(e.GetName(), e.GetLabel(), "set contracts:", e.param.symbol)
        arrChartConfig.push(createChartConfig(e.GetCurrency(), e.param.atrPeriod, e.param.emaPeriod, index))
    })
    var chart = Chart(arrChartConfig)
    chart.reset()

    while (true) {
        _.each(exchanges, function(e, index) {
            process(e, index + index * 4, chart)
            Sleep(500)
        })      
    }
}

function onexit() {
    // record e.state
    var arrState = []
    _.each(exchanges, function(e) {
        arrState.push(e.state)
    })
    Log("record:", arrState)
    _G("arrState", arrState)
}

Paramètres de stratégie:

var params = '[{
        "symbol" : "swap",    // contract code
        "period" : 86400,     // K-line period, 86,400 seconds is a day
        "stopLoss" : 0.07,    // stop loss factor, 0.07 or 7%
        "atrPeriod" : 10,     // ATR indicator parameters
        "emaPeriod" : 10,     // EMA indicator parameters
        "trackRatio" : 1,     // upBand and downBand coefficients
        "openRatio" : 0.1     // The reserved opening percentage, which is not supported for now
    }, {
        "symbol" : "swap",
        "period" : 86400,
        "stopLoss" : 0.07,
        "atrPeriod" : 10,
        "emaPeriod" : 10,
        "trackRatio" : 1,
        "openRatio" : 0.1
    }]'

Captures d'écran de test arrière:

img

img

img

Le code source de la stratégie:https://www.fmz.com/strategy/339344

S'il vous plaît modifier, optimiser, et se référer au vrai bot par vous-même.


Relationnée

Plus de