Ensinar-lhe a escrever estratégias - transplante uma estratégia MyLanguage (Advanced)

Autora:Lydia., Criado: 2022-12-26 18:56:00, Atualizado: 2023-09-20 09:46:34

img

Ensinar a escrever estratégias transplantar uma estratégia MyLanguage (Advanced)

No último artigoEnsinar a escrever estratégias -- transplantar uma estratégia MyLanguage, uma estratégia simples de MyLanguage foi testada para transplante. Se é um MyLanguage mais complexo, como pode ser transplantado em uma estratégia de linguagem JavaScript? Que habilidades há?

Vejamos primeiro a estratégia a ser transplantada:

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

O(* backtest... *)No início da estratégia MyLanguage está o código de configuração para configurações de backtesting. Para facilitar a comparação, uma configuração de backtesting unificada é definida. Esta estratégia também é aleatória, que não é muito complexa (mais complexa do que no último artigo). É uma estratégia representativa. Para transplantar uma estratégia MyLanguage, você deve olhar para toda a estratégia primeiro. O código da estratégia é conciso e você pode ter uma certa compreensão da estratégia geral. Para esta estratégia, vimos que várias funções de indicadorEMA, SMAforam utilizados:

Construir uma roda primeiro.

  • EMA A função de indicador, há funções de biblioteca de indicadores prontas disponíveis diretamente na plataforma FMZ ao escrever estratégias na linguagem JavaScript.TA.MA.

  • SMA O que temos de fazer éSMAIndicador, que encontramos na biblioteca TA do FMZ não suporta a função de indicador SMA, e há diferenças entre o indicador SMA na biblioteca talib e o do MyLanguage.

img

Como podemos ver, a seção de parâmetros tem um parâmetro de pesos, além do parâmetro de período.

A função de indicador SMA na biblioteca talib na documentação da API FMZ é descrita como:

img

Pode-se ver quetalib.SMAé um simples indicador da média móvel. Assim, só podemos implementar um SMA por nós mesmos. Como um desenvolvedor usando a linguagem JavsScript para escrever estratégias, esta também é uma das habilidades necessárias. Afinal, se não houver uma roda pronta, o programa ainda precisa ser executado, basta construir uma.

Para dizer a verdade, não há muita pesquisa sobre indicadores e assim por diante. Geralmente, as pessoas procuram informações se não as entendem. Para a SMA encontrar estas:

img

Parece que o processo de algoritmo desta teoria é bastante confiável, e a implementação é a seguinte:

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
}

Escrever seções preenchidas

O quadro estratégico utiliza o mesmo quadro que o referido no artigoEnsinar a escrever estratégias -- transplantar uma estratégia MyLanguagee preenchidos principalmente em duas partes:

Primeiro, faça o processamento de dados e o cálculo do índice.

img

Vamos tomar esta parte do MyLanguage uma frase de cada vez, função por função:

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

Pode entender-se que o preço mais alto, o preço mais baixo e o preço de encerramento de cada BAR na linha K devem ser somados e depois divididos por 3 para calcular o valor médio e depois salvos como uma matriz, correspondente a cada BAR um por um. Pode ser processado da seguinte forma:

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 função pode ser chamada na função OnTick do loop principal, por exemplo:

// Calculation of indicators
// AP
var ap = CalcAP(records)
    1. Depois de concluído o cálculo do AP, proceder ao cálculoESA:=EMA(AP,N1);:

Aqui, vamos usar os dados de AP calculados na etapa anterior para calcular o ESA. Na verdade, o ESA é a média móvel exponencial do AP, ou seja, o indicador EMA. Então vamos usar AP como os dados e N1 como o parâmetro do indicador EMA para calcular o 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);

Utilize o cálculoAP, ESApara calcular os dadosD- Não. Os comentários ao código podem ser consultados para obter algumas dicas sobre como calcular os 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);O método de cálculo é semelhante ao da etapa 1, e o código é liberado diretamente.
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
}
  • TCI:=EMACI,N2); Basta calcular o indicador EMA para a 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);

Nesta última etapa, a função SMA da roda que construímos antes é usada.

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

A translação de sinais comerciais é muito simples.

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

Após ler estes códigos do MyLanguage, podemos ver que a Cruz de Ouro e o Crossover de Bearish de WT1 e WT2 são usados como condições de abertura. Usando o backtest da estratégia MyLanguage diretamente, observamos que:

img

Pode-se ver a partir da observação do funcionamento real da estratégia MyLanguage que, quando um sinal é detectado na posição de abertura, é realmente para detectar se a posição do BAR no ponto de abertura contando 2 BARs para a frente é uma Cruz de Ouro.

img img

O código de preenchimento da parte de detecção de sinal pode ser escrito 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   
}

Aqui você pode pensar sobre por que as instruções SPK e BPK do MyLanguage podem ser implementadas com o código acima.

Teste de retrocesso

Configuração do teste de regresso:

img

Backtest em MyLanguage:

img

Backtest na versão JavaScript:

img img

O código no início da função OnTick é usado para fazer o backtesting mais rápido. É usado para executar a estratégia baseada no modelo Bar. Se você estiver interessado, você pode analisá-lo em detalhes.

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

O código completo da estratégia de ensino:https://www.fmz.com/strategy/174457

Obrigado por ler.


Mais.