SuperTrend V.1 -- Sistema de Linhas de SuperTendência

Autora:Lydia., Criado: 2022-12-01 11:36:33, Atualizado: 2023-09-11 20:04:38

img

I. Origem da história

O Sr. Ran, meu bom amigo, tem observado este indicador há muito tempo e recomendou-mo antes do dia de Ano Novo para discutir se ele pode ser convertido em quantificação. É uma pena que o procrastinador tenha adiado até agora para ajudá-lo a cumprir tal desejo. Estima-se que um dia vou escrever um tradutor para a língua Pine. Tudo pode ser Python. Bem, sem muita tolice, vamos apresentar a lendária linha de super tendência.

II. Introdução do sistema

Na nova geração de sistema de negociação inteligente no CMC Markets, podemos selecionar Super Trend Line dos indicadores técnicos a serem usados, Podemos ajustar a cor e espessura dos sinais crescentes e decrescentes de acordo com as nossas preferências. Então, o que é um indicador de super tendência? Antes de entender a fórmula do indicador de super tendência, é necessário entender o ATR, porque a super tendência adota o valor ATR para calcular o valor do indicador. Os principais algoritmos são também descritos na seguinte figura:

img

Dê uma breve olhada. Ele descreve principalmente o canal onde HL2 (k-line preço médio) mais n vezes de ATR. Faça uma ruptura de tendência. Mas o artigo é simples, sem algoritmos detalhados, então eu pensei na comunidade mais incrível, TradingView. De facto, está mesmo lá.

img

Olhando para o gráfico, está em linha com a tendência, infelizmente, é apenas um sinal de alarme de alerta.

III. Aprender código fonte

O código não é muito longo, então vamos tentar traduzi-lo.!

img

O código completo do pinheiro é como acima.

VI. Conversão de códigos

Aqui criamos uma nova estratégia no FMZ, chamá-lo de SuperTrend

img

Em seguida, vamos definir dois parâmetros, Fator e Pd

img

A fim de simplificar melhor a operação de código e facilitar a compreensão, precisamos usar o pacote de expansão de dados avançado do python, Pandas (https://pandas.pydata.org/) O FMZ apoia esta biblioteca agora.

  1. Precisamos de importar a biblioteca dos pandas e a biblioteca do tempo.
  2. Na função principal, definir a utilização de contratos trimestrais (principalmente para o okex)
  3. Configure um ciclo doTicker() para detectar uma vez a cada 15 minutos. Execute o código em um período de 15 minutos Então escrevemos a estratégia principal em 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. Precisamos recuperar o OHCLV da K-line, então usamos GetRecords ((()
  2. Importamos os dados recuperados para pandas M15 = pd.DataFrame ((records)
  3. Precisamos modificar o rótulo de cabeçalho da tabela. M15.colunas = [time,open,high,low,close,volume,OpenInterest] Na verdade, é para mudar as letras iniciais de open, high, low e close para minúsculas, para que nossa escrita de código posterior não precise mudar de maiúsculas para minúsculas.
def doTicker(records):
    M15 = pd.DataFrame(records)
    M15.columns = ['time','open','high','low','close','volume','OpenInterest']  
  1. Adicionar uma coluna ao conjunto de dados hl2 hl2=(alto+baixo)/2
#HL2
M15['hl2']=(M15['high']+M15['low'])/2
  1. Então vamos calcular ATR Porque o cálculo ATR precisa importar um comprimento variável, cujo valor é Pd

Em seguida, referimos-nos ao manual do MyLanguage, e os passos do algoritmo do valor médio da amplitude de flutuação real ATR são os seguintes: TR: MAX ((MAX((HIGH-LOW),ABS ((REF ((CLOSE,1)-HIGH)),ABS ((REF ((CLOSE,1)-LOW)); ATR: RMA(TR,N)

O valor TR é o máximo das três diferenças seguintes:

  1. A flutuação entre o preço mais alto e o preço mais baixo no dia de negociação em curso
  2. A flutuação entre o preço de fechamento do dia de negociação anterior e o preço mais elevado do REF do dia de negociação em curso (CONCLUSÃO, 1) - ALTO
  3. A flutuação entre o preço de fechamento do dia de negociação anterior e o preço mais baixo do REF do dia de negociação em curso (CLOSE, 1) - BAIXO Então TR: MAX ((MAX((HIGH-LOW),ABS(REF ((CLOSE,1)-HIGH)),ABS(REF ((CLOSE,1)-LOW));

No cálculo do Python

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

Precisamos configurar um prev_close para recuperar os dados de fechar na linha anterior, ou seja, mover fechar à direita por uma grade para formar um novo parâmetro

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

Em seguida, definimos uma variável intermediária que registra uma 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 uma nova coluna no conjunto de dados e nomeamos como TR. O valor de TR é o maior valor absoluto da variável intermediária, usando as funções abs () e max ()

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

Finalmente, precisamos calcular o valor de ATR, ATR: RMA (TR, N). O parâmetro padrão do ATR é 14.

===

Então o algoritmo ewm é usado para calcular o ema O processo completo de cálculo do ATR é o seguinte:

    #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 Começar a calcular Up e Dn

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

Up=hl2 - ((Fator * atr) Dn=hl2 +(Fator * atr) Não é simples?

Aqui está a secção do código principal das linhas 15-21 da 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

O ponto principal deste parágrafo é expressar que, Se estiver na fase de alta, (linha inferior) TrendUp=max (Up, TrendUp [1]) Se estiver no estágio de queda, (linha superior) TrendDown=min (Dn, TrendDown [1]) Isto é, em uma tendência, o valor ATR tem usado uma tecnologia semelhante à estratégia Bandit Bollinger. Continua a estreitar o outro lado do canal.

Aqui, cada cálculo de TrendUp e TrendDown requer auto-iteração. Ou seja, cada etapa deve ser calculada de acordo com a etapa anterior. Por conseguinte, o conjunto de dados deve ser iterado no loop.

Primeiro, criamos novos campos TrendUp, TrendDown, Trend, linecolor para o conjunto de dados. Em seguida, usamos a gramática fillna (0) para preencher os dados com valor nulo no resultado calculado anteriormente com 0

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

Ativar um loop for Usando a operação ternária Python no loop

    for x in range(len(M15)):

Calcular a tendência TrendUp = MAX(Up,TrendUp[-1]) se fechado[-1]>TrendUp[-1] caso contrário Up Isso significa aproximadamente que se o fechamento anterior> anterior TrendUp é verdadeiro, o valor máximo entre Up e o TrendUp anterior será tomado; caso contrário, o valor Up será tomado e passado para o TrendUp atual

        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]

Da mesma forma, calcule a tendência para baixo TrendDown=min(Dn,TrendDown[-1]) se fechado[-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]

A seguir está a bandeira para calcular a direção de controle. Tendência= 1 se (fechar > Tendência Baixa[-1]) caso contrário (x) x = -1 se (fechado< Tendência de subida[-1]) caso contrário Tendência[-1]

O significado é que se o preço de fechamento>a tendência anterior, tomar o valor de 1 (bullish). Se o preço de fechamento for inferior ao anterior TrendUp, tome o valor de -1 (baixista). Para traduzir em linguagem de imagem é que uma quebra da bandeira de transição da pista superior para alta; e uma quebra da bandeira de transição da pista inferior para baixa.

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

Calcular Tsl e Linecolor Tzl= RendUp se (Tendência==1) caso contrário TrendDown Tsl é o valor usado para representar a SuperTendência na imagem. Significa marcar a faixa descendente na imagem quando estamos em alta, e marcar a faixa superior na imagem quando estamos em baixa. linecolor= verde se (Tendência==1) caso contrário vermelho O significado de linecolor é marcar a linha verde se estamos em alta, e marcar a cor vazia se estamos em baixa (principalmente para o propósito de exibição 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'

As próximas 23-30 linhas de código são principalmente desenhos de gráficos, que não são explicados aqui.

Finalmente, há 2 linhas de código para controlar o sinal de compra e venda Em Tradeview, significa que o sinal é dado após inverter a bandeira Converte a instrução condicional para Python. Se o último sinal de tendência mudar de -1 para 1, significa que a resistência superior foi ultrapassada e a posição longa aberta. Se a última bandeira de tendência mudar de 1 para -1, significa que o suporte para baixo foi excedido e a posição curta aberta.

    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)

O código completo é o seguinte:

    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

Ajustei a estrutura geral do código. E eu fundei as instruções de ordem relacionadas a ir longo e ir curto na estratégia. Aqui está o 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);

Endereço da estratégia pública:https://www.fmz.com/strategy/200625

VI. Reexame e resumo

Selecionámos os dados do ano passado para testes de retrospectiva. Usamos o contrato trimestral OKEX por um período de 15 minutos. Os parâmetros definidos são: Fator = 3 Pd=45 Vol=100 (100 contratos por encomenda) O rendimento anual é de cerca de 33%. De um modo geral, a retirada não é muito grande. A queda acentuada de 312 teve um impacto relativamente grande no sistema, Se não houver 312, os retornos devem ser melhores.

img

VII. Escrever no final

SuperTrend é um sistema de negociação muito bom

O principal princípio do sistema SuperTrend é adotar a estratégia de ruptura do canal ATR (semelhante ao canal de Kent) No entanto, a sua alteração deve-se principalmente ao uso da estratégia de estreitamento do Bandit Bollinger, ou ao inverso do princípio de Donchian. Na operação de mercado, os canais superior e inferior são continuamente estreitados. A fim de conseguir o funcionamento da direção de ruptura do canal (uma vez que o canal atravessa, as faixas superior e inferior retornarão ao valor inicial)

Eu traço, dn, TrendUp e TrendDn separadamente no TradeView, O que facilita a melhor compreensão da estratégia. Veja-se claramente de uma olhada:

img

Além disso, há uma versão do js no github. Eu não sou bom no js, mas parece que há algo errado com a instrução if. O endereço:https://github.com/Dodo33/gekko-supertrend-strategy/blob/master/Supertrend.js

Finalmente, encontrei a versão original. Publicado em 29 de maio de 2013 O autor é Rajandran R. O código C++ foi publicado no fórum Mt4:https://www.mql5.com/en/code/viewcode/10851/128437/Non_Repainting_SuperTrend.mq4Eu entendi grosseiramente o significado de C++, e vou reescrevê-lo quando tiver oportunidade.

Espero que possa aprender a essência dela. É difícil!


Relacionados

Mais.