SuperTrend V.1 -- Sistema de líneas de supertrend

El autor:- ¿ Por qué?, Creado: 2022-12-01 11:36:33, Actualizado: 2023-09-11 20:04:38

img

I. Origen de la historia

El Sr. Ran, mi buen amigo, ha observado este indicador durante mucho tiempo y me lo recomendó antes del día de Año Nuevo para discutir si se puede convertir en cuantificación. Es una lástima que el procrastinador haya tardado hasta ahora en ayudarlo a cumplir tal deseo. De hecho, mi comprensión de los algoritmos ha mejorado rápidamente recientemente. Se estima que algún día escribiré un traductor para el lenguaje Pine. Todo puede ser Python. Bueno, sin demasiadas tonterías, vamos a presentar la legendaria línea de super tendencia.

II. Introducción del sistema

En la nueva generación de sistema de negociación inteligente en CMC Markets, podemos seleccionar Super Trend Line de los indicadores técnicos para usar, Podemos ajustar el color y el grosor de las señales crecientes y disminuyentes de acuerdo con nuestras propias preferencias. Entonces, ¿qué es un indicador de súper tendencia? Antes de entender la fórmula del indicador de súper tendencia, es necesario entender el ATR, porque la súper tendencia adopta el valor ATR para calcular el valor del indicador. Los principales algoritmos también se describen en la siguiente figura:

img

Echa un breve vistazo. Principalmente describe el canal donde HL2 (precio promedio de la línea k) más n veces ATR. Pero el artículo es simple, no hay algoritmo detallado, entonces pensé en la comunidad más increíble, TradingView. De hecho, realmente está ahí.

img

Mirando el gráfico, está en línea con la tendencia, desafortunadamente, es sólo una señal de alarma de alerta.

III. Aprender el código fuente

El código no es demasiado largo, así que intentemos traducirlo.!(っ•̀ω•́)っ))!

img

El código de pinos completo es el anterior.

VI. Conversión de códigos

Aquí creamos una nueva estrategia en FMZ, llamándola SuperTrend

img

A continuación, vamos a establecer dos parámetros, Factor y Pd

img

Para simplificar mejor la operación del código y facilitar la comprensión, necesitamos utilizar el paquete de expansión de datos avanzado de Python, Pandas (https://pandas.pydata.org/) y FMZ apoya esta biblioteca ahora.

  1. Necesitamos importar la biblioteca de pandas y la biblioteca de tiempo
  2. En la función principal, establecer el uso de contratos trimestrales (principalmente para okex)
  3. Configurar un ciclo doTicker() para detectar una vez cada 15 minutos. Ejecuta el código en un período de 15 minutos Luego escribimos la estrategia principal en 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. Necesitamos recuperar el OHCLV de K-line, así que usamos GetRecords ((()
  2. Importamos los datos recuperados a los pandas M15 = pd.DataFrame ((registros)
  3. Necesitamos modificar la etiqueta de encabezado de la tabla. M15.columns = [time,open,high,low,close,volume,OpenInterest] De hecho, es para cambiar las letras iniciales de open, high, low, y close a minúsculas, para que nuestra escritura de código posterior no necesite cambiar de mayúsculas a minúsculas.
def doTicker(records):
    M15 = pd.DataFrame(records)
    M15.columns = ['time','open','high','low','close','volume','OpenInterest']  
  1. Añadir una columna al conjunto de datos hl2 hl2=(alto+bajo)/2
#HL2
M15['hl2']=(M15['high']+M15['low'])/2
  1. Entonces calculemos ATR Porque el cálculo ATR necesita importar una longitud variable, cuyo valor es Pd

Luego nos referimos al manual de MyLanguage, y los pasos del algoritmo del valor medio de la amplitud de fluctuación real de ATR son los siguientes: TR: MAX (MAX) (HIGH-LOW),ABS (REF) (CLOSE,1) (HIGH) (ABS (REF) (CLOSE,1) (LOW)); ATR: RMA (TR,N)

El valor TR es el máximo de las tres diferencias siguientes:

  1. La fluctuación entre el precio más alto y el precio más bajo en el día de negociación actual
  2. La fluctuación entre el precio de cierre del día de negociación anterior y el precio más alto del día de negociación actual REF (CLUSIÓN, 1) - ALTO
  3. La fluctuación entre el precio de cierre del día de negociación anterior y el precio más bajo del día de negociación actual REF (CLOSE, 1) - BAJO Así que TR: MAX ((MAX((HIGH-LOW),ABS ((REF ((CLOSE,1)-HIGH)),ABS ((REF ((CLOSE,1)-LOW));

En el cálculo de Python

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

Necesitamos configurar un prev_close para recuperar los datos de cerrar en la línea anterior, es decir, mover cerrar a la derecha por una cuadrícula para formar un nuevo parámetro

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

A continuación, definimos una variable intermedia que registra una matriz de 3 valores contrastantes para TR. (HIGH-LOW) (high-prev_close) (low-prev_close)

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

Definimos una nueva columna en el conjunto de datos y la nombramos TR. El valor de TR es el mayor valor absoluto de la variable intermedia, utilizando las funciones abs () y max ()

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

Finalmente, necesitamos calcular el valor de ATR, ATR: RMA (TR, N). Se encuentra que el algoritmo RMA es una variante de valor fijo del algoritmo EMA en realidad. N es la variable que importamos. El parámetro predeterminado de ATR es 14.

===

Entonces el algoritmo ewm se utiliza para calcular el ema El proceso completo de cálculo del ATR es el siguiente:

    #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 Comience a calcular hasta y Dn

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

En el caso de las empresas de servicios de telecomunicaciones, el valor de las emisiones se calcula en función de las emisiones de energía. Dn=hl2 +(Factor * atr) ¿No es eso simple?

Aquí está la sección de código principal de las líneas 15-21 de TV

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

El punto principal de este párrafo es expresar que, Si se encuentra en la fase alcista, (línea inferior) TrendUp=max (Up, TrendUp [1]) Si se encuentra en la etapa de caída, (línea superior) Tendencia Baja=min (Dn, Tendencia Baja [1]) Es decir, en una tendencia, el valor ATR ha estado utilizando una tecnología similar a la estrategia Bandit Bollinger. Sigue estrechando el otro lado del canal.

Aquí, cada cálculo de TrendUp y TrendDown requiere auto iteración. Es decir, cada paso debe calcularse de acuerdo con el paso anterior. Por lo tanto, el conjunto de datos debe repetirse en el bucle.

Primero, creamos nuevos campos TrendUp, TrendDown, Trend, linecolor para el conjunto de datos. y darles un valor inicial Luego usamos el fillna (0) gramatical para llenar los datos con valor nulo en el resultado previamente calculado con 0

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

Habilitar un bucle para Usando la operación ternaria de Python en el bucle

    for x in range(len(M15)):

Calcular la tendencia Tendencia hacia arriba = MAX(Alto,Tendencia hacia arriba[-1]) si está cerca[-1]>Tendencia hacia arriba[-1] si no hacia arriba Significa aproximadamente que si el cierre anterior> anterior TrendUp es verdadero, se tomará el valor máximo entre Up y el TrendUp anterior; si no, se tomará el valor Up y se pasará al TrendUp actual.

        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]

Del mismo modo, calcular la tendencia hacia abajo Tendencia baja=min(Dn,Tendencia baja[-1]) si está cerca[-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]

La siguiente es la bandera para el cálculo de la dirección de control. Tendencia= 1 si (cerrar > Tendencia Baja[-1]) en caso contrario (x) x = -1 si (cerca< Tendencia hacia arriba[-1]) de lo contrario Tendencia[-1]

El significado es que si el precio de cierre>el anterior TrendDown, tomar el valor de 1 (bullish). Si el precio de cierre es menor que el TrendUp anterior, tome el valor de -1 (bajista). Para traducir en lenguaje de imagen es que una ruptura de la bandera de transición de la pista superior para alcista; y una ruptura de la bandera de transición de la pista inferior para bajista.

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

Calcular Tsl y Linecolor Tzl= rendUp si (Tendencia==1) de lo contrario Tendencia Baja Tsl es el valor utilizado para representar SuperTrend en la imagen. Significa marcar la pista hacia abajo en la imagen cuando estamos en alcista, y marcar la pista superior en la imagen cuando estamos en bajista. linecolor= verde si (Tendencia==1) de lo contrario rojo El significado de linecolor es marcar la línea verde si estamos en alcista, y marcar el color vacío si estamos en bajista (principalmente con el propósito de mostrar 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'

Las siguientes 23-30 líneas de código son principalmente dibujos de gráficos, que no se explican aquí.

Por último, hay 2 líneas de código para controlar la compra y venta de la señal En Tradeview, significa que la señal se da después de invertir la bandera Convierta la instrucción condicional a Python. Si la última señal de tendencia cambia de -1 a 1, significa que se ha superado la resistencia superior y se abre una posición larga. Si la última bandera de tendencia cambia de 1 a -1, significa que se ha superado el soporte descendente y se abre una posición corta.

    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)

El código completo es el siguiente:

    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. Código completo

He ajustado la estructura general del código. Y fusioné las instrucciones de orden relacionadas con ir largo y ir corto en la estrategia. Aquí está el código completo:

'''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);

Dirección de la estrategia pública:https://www.fmz.com/strategy/200625

VI. Pruebas de retroceso y resumen

Seleccionamos los datos del año pasado para hacer pruebas de retroceso. Usamos el contrato trimestral de OKEX por un período de 15 minutos. Los parámetros establecidos son: Factor = 3 Pd = 45 Vol=100 (100 contratos por orden) El rendimiento anualizado es de alrededor del 33%. Hablando en general, la retirada no es muy grande, La fuerte disminución de 312 tuvo un impacto relativamente grande en el sistema, Si no hay 312, las devoluciones deberían ser mejores.

img

VII. Escribir al final

SuperTrend es un sistema de trading muy bueno.

El principio principal del sistema SuperTrend es adoptar la estrategia de avance del canal ATR (similar al canal de Kent) Sin embargo, su cambio se debe principalmente al uso de la estrategia de estrechamiento del Bandit Bollinger, o al contrario del principio de Donchian. En la operación de mercado, los canales superior e inferior se estrechan continuamente. Con el fin de lograr el funcionamiento de la dirección de avance del canal (una vez que el canal se rompa, las vías superior e inferior volverán al valor inicial)

Trazo, dn, TrendUp y TrendDn por separado en el TradeView, lo que hace más fácil comprender mejor la estrategia. Vean con claridad a simple vista:

img

Además, hay una versión de js en github. No soy bueno en js, pero parece que hay algo mal con la instrucción if. La dirección:https://github.com/Dodo33/gekko-supertrend-strategy/blob/master/Supertrend.js

Finalmente, encontré la versión original. Fue publicado el 29 de mayo de 2013 El autor es Rajandran R. El código C++ fue publicado en el foro Mt4:https://www.mql5.com/en/code/viewcode/10851/128437/Non_Repainting_SuperTrend.mq4He entendido más o menos el significado de C++, y lo volveré a escribir cuando tenga la oportunidad.

Espero que puedas aprender la esencia de ella. ¡Es difícil!


Relacionados

Más.