Enseñarle a escribir estrategias -- trasplantar una estrategia MyLanguage (Advanced)

El autor:- ¿ Por qué?, Creado: 2022-12-26 18:56:00, Actualizado: 2023-09-20 09:46:34

img

Enseñarle a escribir estrategias trasplantar una estrategia de MyLanguage (Advanced)

En el último artículoEnseñar a escribir estrategias -- trasplantar una estrategia MyLanguage, una estrategia simple de MyLanguage ha sido probada para el trasplante. Si es una estrategia de MyLanguage más compleja, ¿cómo se puede trasplantar en una estrategia de lenguaje JavaScript? ¿Qué habilidades hay?

Veamos primero la estrategia para trasplantar:

(*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;

El(* backtest... *)al principio de la estrategia MyLanguage está el código de configuración para la configuración de backtesting. Para facilitar la comparación, se establece una configuración de backtesting unificada. Esta estrategia también es aleatoria, que no es demasiado compleja (más compleja que la del artículo anterior). Es una estrategia representativa. Para trasplantar una estrategia MyLanguage, primero debe mirar toda la estrategia. El código de la estrategia es conciso, y puede tener una cierta comprensión de la estrategia general. Para esta estrategia, hemos visto que varias funciones de indicadorEMA, SMAse han utilizado:

Construye una rueda primero.

  • La EMA La función de indicador, hay funciones de biblioteca de indicadores ya hechas disponibles directamente en la plataforma FMZ cuando se escriben estrategias en lenguaje JavaScript.TA.MA.

  • La SMA Lo que tenemos que hacer esSMAindicador, que encontramos en la biblioteca TA de FMZ no admite la función de indicador SMA, y hay diferencias entre el indicador SMA en la biblioteca talib y el de MyLanguage.

img

Como podemos ver, la sección de parámetros tiene un parámetro de pesos además del parámetro de período.

La función de indicador SMA en la biblioteca talib en la documentación de la API FMZ se describe como:

img

Se puede ver quetalib.SMAes un simple indicador de media móvil. De esta manera, solo podemos implementar un SMA por nosotros mismos. Como desarrollador que usa el lenguaje JavsScript para escribir estrategias, esta también es una de las habilidades necesarias. Después de todo, si no hay una rueda lista, el programa todavía necesita ejecutarse, solo construya una.

En realidad, no hay mucha investigación sobre indicadores, etc. Generalmente, la gente busca información si no la entiende.

img

Parece que el proceso algorítmico de esta teoría es bastante confiable, y la implementación es la siguiente:

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
}

Escribir secciones llenas

El marco estratégico utiliza el mismo marco que en el artículoEnseñar a escribir estrategias -- trasplantar una estrategia MyLanguagey se llena principalmente en dos partes:

En primer lugar, hacer el procesamiento de datos del ticker y el cálculo del índice.

img

Tomemos esta parte de MyLanguage una oración a la vez, función por función:

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

Se puede entender que el precio más alto, el precio más bajo y el precio de cierre de cada BAR en los datos de la línea K deben sumarse y luego dividirse por 3 para calcular el valor medio, y luego guardarse como una matriz, correspondiente a cada BAR uno por uno. Se puede procesar de la siguiente manera:

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 
}

Esta función se puede llamar en el bucle principal de la función OnTick, por ejemplo:

// Calculation of indicators
// AP
var ap = CalcAP(records)
    1. Después de completar el cálculo del AP, proceder al cálculoESA:=EMA(AP,N1);:

Aquí, vamos a utilizar los datos de AP calculados en el paso anterior para calcular el SEC. De hecho, el SEC es el promedio móvil exponencial del AP, es decir, el indicador EMA. Así que vamos a utilizar AP como los datos y N1 como el parámetro del indicador EMA para calcular el indicador 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);

Utilice el cálculoAP, ESApara calcular los datosD¿ Qué pasa? Los comentarios del código aquí se pueden leer para obtener algunos consejos sobre cómo calcular los indicadores.

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);El método de cálculo es similar al paso 1, y el código se publica directamente.
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
}
  • El número de unidades de la unidad de control será el número de unidades de la unidad de control. Solo calcule el indicador EMA para la matriz 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);

En este último paso, se utiliza la función SMA de la rueda que construimos antes.

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 transmisión de señales comerciales es muy simple.

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

Después de leer estos códigos de MyLanguage, podemos ver que la Cruz Dorada y el Cruce Oscuro de WT1 y WT2 se utilizan como condiciones de apertura. Usando el backtest de la estrategia de MyLanguage directamente, observamos que:

img

Se puede ver a partir de la observación del funcionamiento real de la estrategia MyLanguage que cuando se detecta una señal en la posición de apertura, en realidad es para detectar si la posición de la barra en el punto de apertura contando 2 bares hacia adelante es una Cruz de Oro.

img img

El código de relleno de la parte de detección de señal puede escribirse como:

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   
}

Aquí puede pensar en por qué las instrucciones SPK y BPK de MyLanguage pueden ser implementadas con el código anterior.

Prueba de retroceso

Configuración de pruebas de retroceso:

img

Prueba de retroceso en MyLanguage

img

Backtest en la versión de JavaScript:

img img

El código al comienzo de la función OnTick se utiliza para hacer la backtesting más rápida. Se utiliza para ejecutar la estrategia basada en el modelo de Bar. Si está interesado, puede analizarlo en detalle.

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
    }
    ...
    ..
    .

El código completo de la estrategia de enseñanza:https://www.fmz.com/strategy/174457

Gracias por leer.


Más.