Рука-рука учит вас трансплантировать марийский язык (прогресс)

Автор:Маленькие мечты, Создано: 2019-11-13 09:15:56, Обновлено: 2023-10-17 21:23:21

img

Рука-рука учит вас трансплантировать марийский язык (прогресс)

Предыдущая статьяРука-рука учит вас писать стратегии - переносить стратегию на мой язык.Я проверил, как перенести эту стратегию в 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...*)Это конфигурационный код настройки обратной проверки, для удобства сравнения, настройка единой конфигурации обратной проверки. Эта стратегия также является стратегией случайного поиска и не является слишком сложной (относительно более сложной в предыдущей статье), является более репрезентативной стратегией.EMASMA

Изобретение колес

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

  • SMA Мы должны действовать.SMAЭтот показатель, который мы обнаружили в FMZ TA, не поддерживает функцию SMA, а также различие между показателями SMA в талиб и в Ma:imgВы можете видеть, что параметрная часть имеет вес в дополнение к параметру цикла.

    В документации FMZ API описание функции индикатора SMA в библиотеке talib выглядит так:img

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

    Если честно, то исследований по таким показателям мало, и они обычно не понятны.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
    }
    

Составление заполнения

Использование стратегических рамокРука-рука учит вас писать стратегии - переносить стратегию на мой язык.В статье используется одна и та же рамка, в основном заполненная двумя частями:img

В первую очередь, обрабатывать данные о рынке, вычислять показатели.img

Мы рассматриваем эту часть языка по отдельности:

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

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

    function CalcAP (r) {   // AP:=(HIGH+LOW+CLOSE)/3;
        var arrAP = []      // 声明一个空数组
    
        for (var i = 0; i < r.length; i++) {      // r为传入的K线数据,是一个数组,用for遍历这个数组
            v = (r[i].High + r[i].Low + r[i].Close) / 3      // 计算 平均值
            arrAP.push(v)                                    // 添加在 arrAP数组的尾部,arrAP是空的时候尾部就是第一个。
        }  
    
        return arrAP     // 返回 这个平均值数组,即麦语言中计算的 AP 
    }
    

    Функцию можно вызвать в основном цикле функции OnTick, например:

    // 计算指标
    // AP
    var ap = CalcAP(records)
    
  • 2, после завершения AP вычисления, затем вычислениеESA:=EMA(AP,N1);:

    Здесь нужно использовать данные AP, которые мы вычислили в предыдущем шаге, чтобы рассчитать ESA, а на самом деле эта ESA - это "движущаяся средняя индекса" AP, то есть показатель EMA, так что мы можем рассчитать EMA с AP как данными, а с N1 как параметрами показателя EMA.

    function CalcESA (ap, n1) {   // ESA:=EMA(AP,N1);
        if (ap.length <= n1) {    // 如果AP的长度小于指标参数,是无法计算出有效数据的,这个时候让函数返回false。
            return false
        }  
    
        return TA.EMA(ap, n1)
    }
    
  • 3、D:=EMA(ABS(AP-ESA),N1);

    Использование вычисленныхAPESAВычислительные данные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++) {
            // 计算指标数值时,必须判断一下数据的有效性,因为前几次EMA计算可能数组中的开始部分的数据是NaN,或者null
            // 所以必须判断,参与计算的数据都是有效数值才能进行,如果有任何无效数值,就用NaN向arrABS_APminusESA填充
            // 这样计算得到的数据,每个位置和之前的数据都是一一对应的,不会错位。
            if (ap[i] && esa[i] && !isNaN(ap[i]) && !isNaN(esa[i])) {
                v = Math.abs(ap[i] - esa[i])     // 根据ABS(AP-ESA) , 具体计算数值,然后放入arrABS_APminusESA数组
                arrABS_APminusESA.push(v)
            } else {
                arrABS_APminusESA.push(NaN)
            }
        }  
    
        if (arrABS_APminusESA.length <= n1) {
            return false
        }  
    
        return TA.EMA(arrABS_APminusESA, n1)    // 计算数组arrABS_APminusESA的EMA指标,得到数据D(数组结构)
    }
    
  • 4、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:=EMA ((CI,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)   // 使用我们自己实现的SMA函数计算出wt1的SMA指标。
    }
    

Перемещение торговых сигналов очень просто.

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

Читая эти несколько слов кода, можно понять, что для двух линий показателей WT1 и WT2 золотой вилок, мертвый вилок, является условием для открытия позиции. В результате мы обнаружили, что, используя прямую стратегию в этом языке, мы наблюдаем:img

По наблюдениям, выполненным на практике с помощью стратегии языка Мая, при обнаружении сигнала в точке открытия, фактически обнаруживается, является ли местоположение 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")    // 测试
    }
    if (_State == SHORT) {
        _State = COVERSHORT
        Log("COVERSHORT")  // 测试
    }
    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")  // 测试
    }
    if (_State == LONG) {
        _State = COVERLONG
        Log("COVERLONG")  // 测试
    }
    isOK = false   
}

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

Проверка

Проверка конфигурации:img

В этом случае, вы должны быть готовы к тому, что вы не сможете выдержать.img

Проверка версии JavaScript:img img

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

function OnTick(){
    // 驱动策略的行情处理部分
    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

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


Связанные

Больше