Научить писать стратегии - трансплантировать стратегию MyLanguage (продвинутое)

Автор:Лидия., Создано: 2022-12-26 18:56:00, Обновлено: 2023-09-20 09:46:34

img

Научить писать стратегии пересадить стратегию MyLanguage (продвинутое)

В предыдущей статьеНаучить писать стратегии - пересадить стратегию MyLanguageЕсли это более сложный MyLanguage, как его можно трансплантировать в стратегию языка JavaScript? Какие навыки есть?

Давайте сначала посмотрим на стратегию трансплантации:

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

В(* backtest... *)в начале стратегии MyLanguage находится код конфигурации для настроек бэкстестинга. Для облегчения сравнения устанавливается унифицированная конфигурация бэкстестинга. Эта стратегия также случайная, которая не слишком сложна (более сложна, чем в предыдущей статье). Это репрезентативная стратегия. Чтобы перенести стратегию MyLanguage, вы должны сначала посмотреть на всю стратегию. Код стратегии краткий, и вы можете иметь определенное понимание общей стратегии. Для этой стратегии мы видели, что несколько функций индикатораEMA, SMAбыли использованы:

Сначала сооруди колесо.

  • ЕМА Функция индикатора, есть готовые функции библиотеки индикаторов, доступные непосредственно в платформе FMZ при написании стратегий на языке JavaScript.TA.MA.

  • SMA Что нам нужно сделать, этоSMAиндикатор, который мы нашли в библиотеке TA FMZ не поддерживает функцию индикатора SMA, и есть различия между индикатором SMA в библиотеке talib и в MyLanguage.

img

Как мы видим, в разделе параметров есть параметр весов в дополнение к параметру периода.

Функция индикатора SMA в библиотеке talib в документации FMZ API описана следующим образом:

img

Можно заметить, чтоtalib.SMAявляется простым индикатором скользящей средней. Таким образом, мы можем реализовать SMA только сами. Как разработчик, использующий язык JavsScript для написания стратегий, это также один из необходимых навыков. В конце концов, если нет готового колеса, программа все равно должна работать, просто соорудите одно.

По правде говоря, не так много исследований по показателям и т. д. Как правило, люди ищут информацию, если не понимают ее.

img

Кажется, что алгоритм этой теории достаточно надежный, и его реализация выглядит следующим образом:

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
}

Написать заполненные разделы

В рамках стратегии используются те же рамки, что и в статьеНаучить писать стратегии - пересадить стратегию MyLanguageи в основном заполняется двумя частями:

Во-первых, обработка данных и вычисление индекса.

img

Давайте возьмем эту часть MyLanguage одно предложение за другим, функция за функцией:

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

Можно понять, что наивысшая цена, самая низкая цена и цена закрытия каждого BAR в данных строки K должны быть сложены, а затем разделены на 3, чтобы рассчитать среднее значение, а затем сохранены в виде массива, соответствующего каждому BAR один за другим. Он может быть обработан следующим образом:

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 
}

Эта функция может быть вызвана в основной функции цикла OnTick, например:

// Calculation of indicators
// AP
var ap = CalcAP(records)
    1. После того, как расчет ПП завершен, перейти к расчетуESA:=EMA(AP,N1);:

Здесь мы будем использовать данные AP, рассчитанные в предыдущем шаге, для расчета ЕЭС. На самом деле, ЕЭС - это экспоненциальная скользящая средняя AP, то есть индикатор EMA. Итак, мы будем использовать AP в качестве данных и N1 в качестве параметра индикатора EMA для расчета индикатора 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);

Используйте рассчитанныйAP, ESAдля расчета данныхD- Да, конечно. Комментарии к коду здесь можно прочитать для некоторых советов о том, как рассчитать показатели.

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);Метод расчета аналогичен шагу 1, и код выпускается непосредственно.
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); Просто вычислить индикатор EMA для массива 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);

В этом последнем шаге используется функция SMA колеса, которое мы построили ранее.

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

Трансплатация торговых сигналов очень проста.

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

После прочтения этих кодов MyLanguage мы можем увидеть, что Golden Cross и Bearish Crossover WT1 и WT2 используются в качестве условий открытия. Используя прямую обратную проверку стратегии MyLanguage, мы наблюдаем:

img

Из наблюдения за фактической работой стратегии MyLanguage видно, что когда сигнал обнаруживается на позиции открытия, он на самом деле должен обнаружить, является ли позиция BAR в точке открытия, отсчитывающая 2 BAR вперед, Золотым крестом.

img img

Код заполнения части обнаружения сигнала может быть записан как:

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   
}

Здесь вы можете подумать о том, почему инструкции SPK и BPK MyLanguage могут быть реализованы с помощью вышеуказанного кода.

Обратный тест

Конфигурация обратного теста:

img

Бактэст в MyLanguage:

img

Бактэст в версии JavaScript:

img img

Код в начале функции OnTick используется для ускорения обратного тестирования. Он используется для запуска стратегии на основе модели Bar. Если вы заинтересованы, вы можете проанализировать его подробно.

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

Полный код учебной стратегии:https://www.fmz.com/strategy/174457

Спасибо за чтение.


Больше