СуперТренд V.1 -- Система линий супер-тенденции

Автор:Лидия., Создано: 2022-12-01 11:36:33, Обновлено: 2023-09-11 20:04:38

img

I. Происхождение истории

Мистер Ран, мой хороший друг, наблюдал за этим показателем в течение долгого времени и рекомендовал мне его до Нового года, чтобы обсудить, можно ли его преобразовать в количественное определение. Жаль, что прокрастинатор так долго не помогал ему исполнить такое желание. На самом деле, мое понимание алгоритмов быстро улучшилось в последнее время. Считается, что однажды я напишу переводчика для языка Пайн. Все может быть питоном. Ну, без лишних ерунд, давайте представим легендарную линию супер тренда.

II. Введение системы

В новом поколении интеллектуальной торговой системы CMC Markets мы можем выбрать Super Trend Line из технических индикаторов, которые мы будем использовать, Мы можем регулировать цвет и толщину увеличивающихся и уменьшающихся сигналов в соответствии с нашими собственными предпочтениями. Прежде чем понять формулу индикатора супертенда, необходимо понять ATR, потому что супертенд использует значение ATR для расчета значения индикатора. Основные алгоритмы также описаны на следующей рисунке:

img

В основном, это описывает канал, где HL2 (средняя цена k-линии) плюс n раз ATR. Но статья простая, без подробного алгоритма, и я придумал самое удивительное сообщество, TradingView. Действительно, оно действительно есть.

img

Если посмотреть на график, это соответствует тенденции, но, к сожалению, это всего лишь сигнал тревоги.

III. Изучение исходного кода

Код не слишком длинный, так что давайте попробуем перевести его.!

img

Полный код сосны - как выше.

VI. Преобразование кодов

Здесь мы создаем новую стратегию на FMZ, назовем ее SuperTrend

img

Далее, мы установим два параметра, Фактор и Pd

img

Чтобы лучше упростить работу кода и облегчить понимание, мы должны использовать расширенный пакет расширения данных Python Pandas (https://pandas.pydata.org/) FMZ поддерживает эту библиотеку сейчас.

  1. Нам нужно импортировать библиотеку панд и библиотеку времени
  2. В основной функции установить использование квартальных контрактов (главным образом для okex)
  3. Установите цикл doTicker ((() для обнаружения один раз в 15 минут. Запустите код в течение 15 минут Затем мы запишем основную стратегию в doTicker ().
import pandas as pd
import time

def main():
    exchange.SetContractType("quarter")
    preTime = 0
    Log(exchange.GetAccount())
    while True:
        records = exchange.GetRecords(PERIOD_M15)
        if records and records[-2].Time > preTime:
            preTime = records[-2].Time
            doTicker(records[:-1])
        Sleep(1000 *60)
  1. Нам нужно получить OHCLV K-линии, так что мы используем GetRecords()
  2. Мы импортируем полученные данные в панды M15 = pd.DataFrame ((записи)
  3. Нам нужно изменить заголовок таблицы. M15.columns = [time,open,high,low,close,volume,OpenInterest] На самом деле, это изменить начальные буквы open, high, low, и close в малые буквы, так что наше более позднее написание кода не нужно менять с больших букв в малые.
def doTicker(records):
    M15 = pd.DataFrame(records)
    M15.columns = ['time','open','high','low','close','volume','OpenInterest']  
  1. Добавить колонку в набор данных hl2 hl2=(high+low)/2
#HL2
M15['hl2']=(M15['high']+M15['low'])/2
  1. Тогда давайте вычислим ATR Поскольку для расчета ATR необходимо импортировать переменную длину, значение которой Pd

Затем мы ссылаемся на руководство MyLanguage, и алгоритм шагов среднего значения реальной амплитуды флуктуации ATR следующие: TR: MAX ((MAX ((((HIGH-LOW),ABS ((REF ((CLOSE,1) -HIGH)),ABS ((REF ((CLOSE,1) -LOW)); ATR: RMA ((TR,N)

Значение TR - это максимум из следующих трех различий:

  1. Колебания между самой высокой и самой низкой ценой на текущий торговый день HIGH-LOW
  2. Колебания между ценой закрытия предыдущего дня торговли и самой высокой ценой текущего дня торговли (REF) (CLOSE, 1) - HIGH
  3. Колебания между ценой закрытия предыдущего дня торговли и самой низкой ценой текущего дня торговли (REF) (CLOSE, 1) - LOW Так что TR: MAX ((MAX ((((HIGH-LOW),ABS ((REF ((CLOSE,1)-HIGH)),ABS ((REF ((CLOSE,1)-LOW));

При расчете Python

M15['prev_close']=M15['close'].shift(1)

Нам нужно настроить prev_close для получения данных закрыть в предыдущей строке, то есть, переместить закрыть направо одной сетки, чтобы сформировать новый параметр

ranges= [M15['high'] - M15['low'],M15['high']-M15['prev_close'],M15['low']-M15['prev_close']]

Далее мы определяем промежуточную переменную, которая записывает массив из 3 контрастных значений для TR. (HIGH-LOW) (high-prev_close) (low-prev_close)

M15['tr'] = pd.DataFrame(ranges).T.abs().max(axis=1)

Мы определяем новую колонку в наборе данных и называем ее TR. Значение TR - это самое большое абсолютное значение промежуточной переменной, используя функции abs () и max ()

    alpha = (1.0 / length) if length > 0 else 0.5
    M15['atr']=M15['tr'].ewm(alpha=alpha, min_periods=length).mean()

Наконец, нам нужно вычислить значение ATR, ATR: RMA (TR, N). Оказалось, что алгоритм RMA является фиксированным вариантом алгоритма EMA. N - это переменная, которую мы импортируем.

===

Затем алгоритм ewm используется для расчета ema Полный процесс расчета ATR выглядит следующим образом:

    #ATR(PD)
    length=Pd
    M15['prev_close']=M15['close'].shift(1)
    ranges= [M15['high'] - M15['low'],M15['high']-M15['prev_close'],M15['low']-M15['prev_close']]
    M15['tr'] = pd.DataFrame(ranges).T.abs().max(axis=1)
    alpha = (1.0 / length) if length > 0 else 0.5
    M15['atr']=M15['tr'].ewm(alpha=alpha, min_periods=length).mean()

9 Начните вычислять Up и Dn

    M15['Up']=M15['hl2']-(Factor*M15['atr'])
    M15['Dn']=M15['hl2']+(Factor*M15['atr'])

Up=hl2 - ((Фактор * atr) Dn=hl2 +(Фактор * atr) Разве это не просто?

Вот основная часть кода из строк 15-21 из ТВ

TrendUp=close[1]>TrendUp[1]? max(Up,TrendUp[1]) : Up
TrendDown=close[1]<TrendDown[1]? min(Dn,TrendDown[1]) : Dn

Trend = close > TrendDown[1] ? 1: close< TrendUp[1]? -1: nz(Trend[1],1)
Tsl = Trend==1? TrendUp: TrendDown

linecolor = Trend == 1 ? green : red

Основным пунктом данного пункта является выражение того, что Если он находится в бычьей стадии, (нижняя линия) TrendUp=max (Up, TrendUp [1]) Если он находится в стадии падения, (верхняя линия) TrendDown=min (Dn, TrendDown [1]) То есть, в тренде, значение ATR использует технологию, аналогичную стратегии Бандита Боллинджера. Продолжайте сужать другую сторону канала.

Здесь каждый расчет TrendUp и TrendDown требует самоитерации. То есть каждый шаг должен быть рассчитан в соответствии с предыдущим шагом. Следовательно, набор данных должен быть итерационным в цикле.

Сначала мы создаем новые поля TrendUp, TrendDown, Trend, linecolor для набора данных. Затем мы используем грамматический fillna (0) для заполнения данных с нулевым значением в ранее рассчитанном результате с 0

    M15['TrendUp']=0.0
    M15['TrendDown']=0.0
    M15['Trend']=1
    M15['Tsl']=0.0
    M15['linecolor']='Homily'
    M15 = M15.fillna(0)

Включить цикл " for " Использование тройной операции Python в петле

    for x in range(len(M15)):

Вычислить TrendUp TrendUp = MAX(Up,TrendUp[-1]) если близко[-1]>TrendUp[-1] в противном случае Up Это приблизительно означает, что если предыдущее закрытие>предыдущее TrendUp верно, то будет принято максимальное значение между Up и предыдущим TrendUp; если нет, то значение Up будет принято и передано текущему TrendUp.

        M15['TrendUp'].values[x] = max(M15['Up'].values[x],M15['TrendUp'].values[x-1]) if (M15['close'].values[x-1]>M15['TrendUp'].values[x-1]) else M15['Up'].values[x]

Аналогичным образом, вычислить TrendDown TrendDown=min(Dn,TrendDown[-1]) если близко[-1]

        M15['TrendDown'].values[x] = min(M15['Dn'].values[x],M15['TrendDown'].values[x-1]) if (M15['close'].values[x-1]<M15['TrendDown'].values[x-1]) else M15['Dn'].values[x]

Следующий флаг для расчета направления управления. Trend= 1 если (закрыть > TrendDown[-1]) иначе (x) x = -1 если (close< TrendUp[-1]) в противном случае Trend[-1]

Это означает, что если цена закрытия>предыдущий TrendDown, возьмите значение 1 (бычий). Если цена закрытия ниже предыдущего TrendUp, возьмите значение -1 (медвежьей). Если нет, возьмите предыдущий Trend (что означает неизменный) Если перевести на язык образа, то это прорыв верхнего флага переходного пути для бычьего; и прорыв нижнего флага переходного пути для медвежьего.

        M15['Tsl'].values[x] = M15['TrendUp'].values[x] if  (M15['Trend'].values[x]==1) else M15['TrendDown'].values[x]

Вычислить Tsl и Linecolor Tsl=RendUp если (Trend==1) иное TrendDown Tsl - это значение, используемое для представления SuperTrend на изображении. Это означает, что мы отмечаем снижающийся трек на изображении, когда мы находимся в бычьем, и отмечаем верхний трек на изображении, когда мы находимся в медленном. linecolor= зеленый если (Тенденция==1) иначе красный Значение линии цвета - отметить зеленую линию, если мы находимся в бычьем, и отметить пустой цвет, если мы находимся в медвежьем (главным образом для целей Tradeview отображения)

        M15['Tsl'].values[x] = M15['TrendUp'].values[x] if  (M15['Trend'].values[x]==1) else M15['TrendDown'].values[x]
        M15['linecolor'].values[x]= 'green' if ( M15['Trend'].values[x]==1) else  'red'

Следующие 23-30 строк кода - это в основном чертежи сюжетов, которые здесь не объясняются.

Наконец, есть 2 строки кода для управления сигналом покупки и продажи В Tradeview, это означает, что сигнал дается после обратного флага Конвертируйте условный комментарий в Python. Если последний флаг тренда меняется с -1 на 1, это означает, что верхнее сопротивление превышено и открыта длинная позиция. Если последний флаг тренда меняется с 1 на -1, это означает, что поддержка вниз превышена и открыта короткая позиция.

    if(M15['Trend'].values[-1] == 1 and M15['Trend'].values[-2] == -1):
        Log('SuperTrend V.1 Alert Long',"Create Order Buy)
    if(M15['Trend'].values[-1] == -1 and M15['Trend'].values[-2] == 1):
        Log('SuperTrend V.1 Alert Long',"Create Order Sell)

Полный код:

    M15['TrendUp']=0.0
    M15['TrendDown']=0.0
    M15['Trend']=1
    M15['Tsl']=0.0
    M15['linecolor']='Homily'
    M15 = M15.fillna(0)
    
    for x in range(len(M15)):
        M15['TrendUp'].values[x] = max(M15['Up'].values[x],M15['TrendUp'].values[x-1]) if (M15['close'].values[x-1]>M15['TrendUp'].values[x-1]) else M15['Up'].values[x]
        M15['TrendDown'].values[x] = min(M15['Dn'].values[x],M15['TrendDown'].values[x-1]) if (M15['close'].values[x-1]<M15['TrendDown'].values[x-1]) else M15['Dn'].values[x]
        M15['Trend'].values[x] = 1 if (M15['close'].values[x] > M15['TrendDown'].values[x-1]) else ( -1 if (M15['close'].values[x]< M15['TrendUp'].values[x-1])else M15['Trend'].values[x-1] )
        M15['Tsl'].values[x] = M15['TrendUp'].values[x] if  (M15['Trend'].values[x]==1) else M15['TrendDown'].values[x]
        M15['linecolor'].values[x]= 'green' if ( M15['Trend'].values[x]==1) else  'red'
        
    if(M15['Trend'].values[-1] == 1 and M15['Trend'].values[-2] == -1):
        Log('SuperTrend V.1 Alert Long',"Create Order Buy)
        Log('Tsl=',Tsl)
    if(M15['Trend'].values[-1] == -1 and M15['Trend'].values[-2] == 1):
        Log('SuperTrend V.1 Alert Long',"Create Order Sell)
        Log('Tsl=',Tsl)

img img

V. Полный код

Я скорректировал структуру кода. И я объединил инструкции, связанные с покупкой и продажей в стратегию. Вот полный код:

'''backtest
start: 2019-05-01 00:00:00
end: 2020-04-21 00:00:00
period: 15m
exchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD"}]
'''

import pandas as pd
import time

def main():
    exchange.SetContractType("quarter")
    preTime = 0
    Log(exchange.GetAccount())
    while True:
        records = exchange.GetRecords(PERIOD_M15)
        if records and records[-2].Time > preTime:
            preTime = records[-2].Time
            doTicker(records[:-1])
        Sleep(1000 *60)

       
def doTicker(records):
    #Log('onTick',exchange.GetTicker())
    M15 = pd.DataFrame(records)

    #Factor=3
    #Pd=7
    
    M15.columns = ['time','open','high','low','close','volume','OpenInterest']  
    
    #HL2
    M15['hl2']=(M15['high']+M15['low'])/2

    #ATR(PD)
    length=Pd
    M15['prev_close']=M15['close'].shift(1)
    ranges= [M15['high'] - M15['low'],M15['high']-M15['prev_close'],M15['low']-M15['prev_close']]
    M15['tr'] = pd.DataFrame(ranges).T.abs().max(axis=1)
    alpha = (1.0 / length) if length > 0 else 0.5
    M15['atr']=M15['tr'].ewm(alpha=alpha, min_periods=length).mean()


    M15['Up']=M15['hl2']-(Factor*M15['atr'])
    M15['Dn']=M15['hl2']+(Factor*M15['atr'])
    
    M15['TrendUp']=0.0
    M15['TrendDown']=0.0
    M15['Trend']=1
    M15['Tsl']=0.0
    M15['linecolor']='Homily'
    M15 = M15.fillna(0)

    for x in range(len(M15)):
        M15['TrendUp'].values[x] = max(M15['Up'].values[x],M15['TrendUp'].values[x-1]) if (M15['close'].values[x-1]>M15['TrendUp'].values[x-1]) else M15['Up'].values[x]
        M15['TrendDown'].values[x] = min(M15['Dn'].values[x],M15['TrendDown'].values[x-1]) if (M15['close'].values[x-1]<M15['TrendDown'].values[x-1]) else M15['Dn'].values[x]
        M15['Trend'].values[x] = 1 if (M15['close'].values[x] > M15['TrendDown'].values[x-1]) else ( -1 if (M15['close'].values[x]< M15['TrendUp'].values[x-1])else M15['Trend'].values[x-1] )
        M15['Tsl'].values[x] = M15['TrendUp'].values[x] if  (M15['Trend'].values[x]==1) else M15['TrendDown'].values[x]
        M15['linecolor'].values[x]= 'Long' if ( M15['Trend'].values[x]==1) else  'Short'
 

    linecolor=M15['linecolor'].values[-2]
    close=M15['close'].values[-2]
    Tsl=M15['Tsl'].values[-2] 


    if(M15['Trend'].values[-1] == 1 and M15['Trend'].values[-2] == -1):

        Log('SuperTrend V.1 Alert Long','Create Order Buy')
        Log('Tsl=',Tsl)
        position = exchange.GetPosition()
        if len(position) > 0:
            Amount=position[0]["Amount"]
            exchange.SetDirection("closesell")
            exchange.Buy(_C(exchange.GetTicker).Sell*1.01, Amount);
        
        exchange.SetDirection("buy")
        exchange.Buy(_C(exchange.GetTicker).Sell*1.01, vol);

    if(M15['Trend'].values[-1] == -1 and M15['Trend'].values[-2] == 1):
        Log('SuperTrend V.1 Alert Long','Create Order Sell')
        Log('Tsl=',Tsl)
        position = exchange.GetPosition()
        if len(position) > 0:
            Amount=position[0]["Amount"]
            exchange.SetDirection("closebuy")
            exchange.Sell(_C(exchange.GetTicker).Buy*0.99,Amount);
        exchange.SetDirection("sell")
        exchange.Sell(_C(exchange.GetTicker).Buy*0.99, vol*2);

Адрес общественной стратегии:https://www.fmz.com/strategy/200625

VI. Обратное тестирование и обобщение

Мы выбрали данные прошлого года для обратного тестирования. Мы используем квартальный контракт OKEX на 15 минут. Установленные параметры: Фактор = 3 Pd=45 Vol=100 (100 контрактов на каждый заказ) Годовая доходность составляет около 33%. Вообще-то, вывод не очень большой, Резкое сокращение 312 имело относительно большое влияние на систему, Если нет 312, то доходы должны быть лучше.

img

VII. Напишите в конце

SuperTrend - очень хорошая торговая система.

Основной принцип системы SuperTrend заключается в принятии стратегии прорыва канала ATR (аналогичной каналу Кента) Однако его изменение обусловлено в основном использованием стратегии сужения Бандита Боллинджера, или обратного принципа Донкиана. При рыночной операции верхние и нижние каналы постоянно сужаются. Для достижения работы рулевого прорыва канала. (После прорыва канала верхние и нижние рельсы вернутся к исходному значению)

Я выставляю, dn, TrendUp и TrendDn отдельно на TradeView, что облегчает понимание стратегии. Посмотрите на это на первый взгляд:

img

Кроме того, есть версия js на github. Я не очень хорош в js, но, похоже, что что-то не так с if-указанием. Адрес:https://github.com/Dodo33/gekko-supertrend-strategy/blob/master/Supertrend.js

Наконец-то я нашла оригинальную версию. Опубликовано 29 мая 2013 Автор - Раджандран Р. Код C++ был опубликован на форуме Mt4:https://www.mql5.com/en/code/viewcode/10851/128437/Non_Repainting_SuperTrend.mq4Я примерно понял смысл C++, и перепишу его, когда будет возможность.

Надеюсь, вы сможете извлечь из него суть. Это сложно!


Связанные

Больше