Apprendre à écrire des stratégies - transplanter une stratégie MyLanguage (Advanced)

Auteur:Je ne sais pas., Créé: 2022-12-26 18:56:00, Mis à jour: 2023-09-20 09:46:34

img

Apprendre à écrire des stratégies transplanter une stratégie MyLanguage (avancée)

Dans le dernier articleApprendre à écrire des stratégies -- transplanter une stratégie MyLanguage, une stratégie MyLanguage simple a été testée pour la transplantation. S'il s'agit d'une MyLanguage plus complexe, comment peut-elle être transplantée dans une stratégie de langage JavaScript? Quelles compétences y a-t-il?

Examinons d'abord la stratégie à transplanter:

(*backtest
start: 2019-05-01 00:00:00
end: 2019-11-12 00:00:00
period: 1d
exchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD"}]
args: [["SlideTick",10,126961],["ContractType","quarter",126961]]
*)

N1:=10;
N2:=21;
AP:=(HIGH+LOW+CLOSE)/3;
ESA:=EMA(AP,N1);
D:=EMA(ABS(AP-ESA),N1);
CI:=(AP-ESA)/(0.015*D);
TCI:=EMA(CI,N2);
WT1:TCI;
WT2:SMA(WT1,4,1);
AA:=CROSS(WT1,WT2);
BB:=CROSSDOWN(WT1,WT2);
REF(AA,1),BPK;
REF(BB,1),SPK;

Le(* backtest... *)au début de la stratégie MyLanguage est le code de configuration pour les paramètres de backtesting. Pour faciliter la comparaison, une configuration de backtesting unifiée est définie. Cette stratégie est également aléatoire, ce qui n'est pas trop complexe (plus complexe que dans l'article précédent). C'est une stratégie représentative. Pour transplanter une stratégie MyLanguage, vous devez d'abord regarder toute la stratégie. Le code de la stratégie est concis, et vous pouvez avoir une certaine compréhension de la stratégie globale. Pour cette stratégie, nous avons vu que plusieurs fonctions d'indicateurEMA, SMAont été utilisés:

Construis d'abord une roue.

  • Le taux d'intérêt La fonction indicateur, il y a des fonctions de bibliothèque d'indicateurs prêtes à l'emploi directement disponibles dans la plateforme FMZ lors de l'écriture de stratégies en langage JavaScript.TA.MA.

  • Le SMA Ce que nous devons faire, c'est leSMAl'indicateur, que nous avons trouvé dans la bibliothèque TA de FMZ ne prend pas en charge la fonction d'indicateur SMA, et il y a des différences entre l'indicateur SMA dans la bibliothèque talib et celui de MyLanguage.

img

Comme nous pouvons le voir, la section paramètres a un paramètre de poids en plus du paramètre de la période.

La fonction d'indicateur SMA dans la bibliothèque talib dans la documentation de l'API FMZ est décrite comme suit:

img

On peut voir quetalib.SMAest un simple indicateur de moyenne mobile. De cette façon, nous ne pouvons implémenter un SMA que par nous-mêmes. En tant que développeur utilisant le langage JavsScript pour écrire des stratégies, c'est aussi l'une des compétences nécessaires. Après tout, s'il n'y a pas de roue prête à l'emploi, le programme doit encore s'exécuter, il suffit de construire une.

Pour être honnête, il n'y a pas beaucoup de recherches sur les indicateurs, etc. Généralement, les gens recherchent des informations s'ils ne les comprennent pas.

img

Il semble que le processus algorithmique de cette théorie soit assez fiable, et la mise en œuvre est la suivante:

function SMA (arr, n, m) {
    var sma = []
    var currSMA = null
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] && !isNaN(arr[i])) {
            if (!currSMA) {
                currSMA = arr[i]
                sma.push(currSMA)
                continue
            }  

            // [M*C2+(N-M)*S1]/N
            currSMA = (m * arr[i] + (n - m) * currSMA) / n
            sma.push(currSMA)
        } else {
            sma.push(NaN)
        }
    }  

    return sma
}

Écrire des sections remplies

Le cadre stratégique utilise le même cadre que celui de l'articleApprendre à écrire des stratégies -- transplanter une stratégie MyLanguageet rempli principalement en deux parties:

Tout d'abord, le traitement des données et le calcul de l'index.

img

Prenons cette partie de MyLanguage une phrase à la fois, fonction par fonction:

    1. AP:=(HIGH+LOW+CLOSE)/3;

On peut comprendre que le prix le plus élevé, le prix le plus bas et le prix de clôture de chaque BAR dans les données de la ligne K doivent être additionnés, puis divisés par 3 pour calculer la valeur moyenne, puis enregistrés sous forme d'un tableau correspondant à chaque BAR un par un. Il peut être traité comme suit:

function CalcAP (r) {   // AP:=(HIGH+LOW+CLOSE)/3;
    var arrAP = []      // Declare an empty array

    for (var i = 0; i < r.length; i++) {      // r is the incoming K-line data, which is an array, use for to traverse this array.
        v = (r[i].High + r[i].Low + r[i].Close) / 3      // Calculate the average value.
        arrAP.push(v)                                    // Add to the end of the arrAP array, the end is the first when arrAP is empty.
    }  

    return arrAP     // Returns this average array, i.e., the AP calculated in the MyLanguage 
}

Cette fonction peut être appelée dans la fonction OnTick de la boucle principale, par exemple:

// Calculation of indicators
// AP
var ap = CalcAP(records)
    1. Une fois le calcul de l'AP terminé, procéder au calculESA:=EMA(AP,N1);:

Ici, nous utiliserons les données de l'AP calculées dans l'étape précédente pour calculer l'ESA. En fait, l'ESA est la moyenne mobile exponentielle de l'AP, c'est-à-dire l'indicateur EMA. Nous utiliserons donc AP comme données et N1 comme paramètre de l'indicateur EMA pour calculer l'indicateur EMA.

function CalcESA (ap, n1) {   // ESA:=EMA(AP,N1);
    if (ap.length <= n1) {    // If the AP length is less than the indicator parameter, valid data cannot be calculated. At this time, let the function return false.
        return false
    }  

    return TA.EMA(ap, n1)
}
    1. D:=EMA(ABS(AP-ESA),N1);

Utilisez le calculAP, ESApour calculer les donnéesDJe suis désolée. Les commentaires du code peuvent être lus ici pour obtenir quelques conseils sur la façon de calculer les indicateurs.

function CalcD (ap, esa, n1) {    // D:=EMA(ABS(AP-ESA),N1);
    var arrABS_APminusESA = []
    if (ap.length != esa.length) {
        throw "ap.length != esa.length"
    }  

    for (var i = 0; i < ap.length; i++) {
        // When calculating the value of the indicator, it is necessary to determine the validity of the data, because the first few EMA calculations may be the beginning of the array of data is NaN, or null.
        // So it must be judged that the data involved in the calculation are all valid values to proceed, and if there are any invalid values, they are filled with NaN to arrABS_APminusESA.
        // The data thus calculated, each position corresponds to the previous data one by one, without misalignment.
        if (ap[i] && esa[i] && !isNaN(ap[i]) && !isNaN(esa[i])) {
            v = Math.abs(ap[i] - esa[i])     // According to ABS(AP-ESA), the specific value is calculated and put into the arrABS_APminusESA array.
            arrABS_APminusESA.push(v)
        } else {
            arrABS_APminusESA.push(NaN)
        }
    }  

    if (arrABS_APminusESA.length <= n1) {
        return false
    }  

    return TA.EMA(arrABS_APminusESA, n1)    // Calculate the EMA indicator of the array arrABS_APminusESA and get the data D (array structure).
}
    1. CI:=(AP-ESA)/(0.015*D);La méthode de calcul est similaire à l'étape 1 et le code est publié directement.
function CalcCI (ap, esa, d) {    // CI:=(AP-ESA)/(0.015*D);
    var arrCI = []
    if (ap.length != esa.length || ap.length != d.length) {
        throw "ap.length != esa.length || ap.length != d.length"
    }
    for (var i = 0; i < ap.length; i++) {
        if (ap[i] && esa[i] && d[i] && !isNaN(ap[i]) && !isNaN(esa[i]) && !isNaN(d[i])) {
            v = (ap[i] - esa[i]) / (0.015 * d[i])
            arrCI.push(v)
        } else {
            arrCI.push(NaN)
        }
    }  

    if (arrCI.length == 0) {
        return false
    }  

    return arrCI
}
  • Le nombre d'équipements utilisés est déterminé par le système de mesure de la température. Calculez simplement l'indicateur EMA pour le tableau CI.
function CalcTCI (ci, n2) {   // TCI:=EMA(CI,N2);
    if (ci.length <= n2) {
        return false
    }  

    return TA.EMA(ci, n2)
}
  • WT2:SMA ((WT1,4,1);

Dans cette dernière étape, la fonction SMA de la roue que nous avons construite avant est utilisée.

function CalcWT2 (wt1) {    // WT2:SMA(WT1,4,1);
    if (wt1.length <= 4) {
        return false 
    }  

    return SMA(wt1, 4, 1)   // The SMA indicator for wt1 is calculated by using our own implementation of the SMA function.
}

La transcription des signaux de trading est très simple.

AA:=CROSS(WT1,WT2);
BB:=CROSSDOWN(WT1,WT2);
REF(AA,1),BPK;
REF(BB,1),SPK;

Après avoir lu ces codes de MyLanguage, nous pouvons voir que le Golden Cross et Bearish Crossover de WT1 et WT2 sont utilisés comme conditions d'ouverture. En utilisant directement le backtest de la stratégie MyLanguage, nous observons que:

img

Il ressort de l'observation du fonctionnement réel de la stratégie MyLanguage que lorsqu'un signal est détecté à la position d'ouverture, il s'agit en réalité de détecter si la position du BAR au point d'ouverture comptant 2 BAR en avant est une Croix d'Or. La figure ci-dessus montre clairement que:

img img

Le code de remplissage de la partie de détection du signal peut être écrit comme suit:

if ((_State == IDLE || _State == SHORT) && wt1[wt1.length - 4] < wt2[wt2.length - 4] && wt1[wt1.length - 3] > wt2[wt2.length - 3]) {
    if (_State == IDLE) {
        _State = OPENLONG
        Log("OPENLONG")    // test
    }
    if (_State == SHORT) {
        _State = COVERSHORT
        Log("COVERSHORT")  // test
    }
    isOK = false  
}

if ((_State == IDLE || _State == LONG) && wt1[wt1.length - 4] > wt2[wt2.length - 4] && wt1[wt1.length - 3] < wt2[wt2.length - 3]) {
    if (_State == IDLE) {
        _State = OPENSHORT
        Log("OPENSHORT")  // test
    }
    if (_State == LONG) {
        _State = COVERLONG
        Log("COVERLONG")  // test
    }
    isOK = false   
}

Ici, vous pouvez réfléchir à la raison pour laquelle les instructions SPK et BPK de MyLanguage peuvent être implémentées avec le code ci-dessus.

Test de retour

Configuration des tests antérieurs:

img

Test de retour dans MyLanguage:

img

Test de retour dans la version JavaScript:

img img

Le code au début de la fonction OnTick est utilisé pour rendre le backtesting plus rapide. Il est utilisé pour exécuter la stratégie basée sur le modèle Bar. Si vous êtes intéressé, vous pouvez l'analyser en détail.

function OnTick(){
    // The ticker processing part of the driving strategy.
    var records = _C(exchange.GetRecords)
    if (records[records.length - 1].Time == preTime) {
        if (isOK) {
            Sleep(500)
            return 
        }
    } else {
        preTime = records[records.length - 1].Time
    }
    ...
    ..
    .

Le code complet de la stratégie pédagogique:https://www.fmz.com/strategy/174457

Merci d'avoir lu.


Plus de