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.
En la nueva generación de sistema de negociación inteligente en CMC Markets, podemos seleccionar
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í.
Mirando el gráfico, está en línea con la tendencia, desafortunadamente, es sólo una señal de alarma de alerta.
El código no es demasiado largo, así que intentemos traducirlo.!(っ•̀ω•́)っ
El código de pinos completo es el anterior.
Aquí creamos una nueva estrategia en FMZ, llamándola SuperTrend
A continuación, vamos a establecer dos parámetros, Factor y Pd
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.
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):
M15 = pd.DataFrame(records)
M15.columns = ['time','open','high','low','close','volume','OpenInterest']
#HL2
M15['hl2']=(M15['high']+M15['low'])/2
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:
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=
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)
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
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.
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:
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!