Type/to search
0
Follow
48
Followers
SuperTrend V.1--Sistema de Super Trend Line
Original
Created 2020-04-20 22:10:36  Updated 2024-12-12 21:03:30
 28
 12168

img

1. Origem da história

Meu bom amigo Ran vem observando esse indicador há muito tempo e o recomendou a mim antes do Ano Novo para discutir se ele poderia ser convertido em uma forma quantitativa.
Infelizmente, sofri de procrastinação e não o ajudei a realizar seu desejo até agora. Na verdade, meu entendimento de algoritmos fez um grande progresso recentemente.
Pretendo escrever um tradutor de pinho um dia. Tudo pode ser python. .
Ok, sem mais delongas, vamos apresentar esta lendária super tendência. .

2. Introdução ao sistema

Nova geração de sistema de negociação inteligente da CMC Markets - Supertrend
Aqui está um artigo apresentando esse sistema.
img

Na nova geração do sistema de negociação inteligente da CMC Markets, selecione "Super Trend Line" nos indicadores técnicos para acessá-lo.
Conforme mostrado na figura, você pode ajustar a "cor e a espessura" dos sinais ascendentes e descendentes de acordo com suas preferências.
Então, o que é o indicador de supertendência? Antes de entender a fórmula do indicador supertrend, é necessário entender o ATR porque o supertrend usa valores de ATR para calcular os valores do indicador.

O algoritmo principal também é apresentado na imagem abaixo.
img

À primeira vista, a descrição principal é um canal de HL2 (preço médio da linha K) multiplicado por n vezes ATR. Crie uma nova tendência.
Mas o artigo é bastante breve. Não há um algoritmo detalhado. Então pensei na melhor comunidade Tradingview.
Não é de surpreender. Com certeza, está lá.
img

A julgar pelo gráfico, ele é bastante consistente com a tendência. Mas infelizmente é apenas um sinal de alerta.

3. Estude o código fonte

O código não parece muito longo, então vamos traduzi-lo e testá-lo. ! (っ•̀ω•́)っ✎⁾⁾!
img
O código completo do pinheiro é como acima. .

4. Conversão de código

Aqui criamos uma nova estratégia no FMZ e a chamamos de SuperTrade
img

Em seguida, definimos dois parâmetros Factor e Pd
img

Para simplificar melhor a operação do código e torná-lo mais fácil de entender, precisamos usar o pacote de expansão de dados avançado do Pythonpandas

Durante o almoço, perguntei à professora Mengmeng se a FMZ apoia esta biblioteca. Verifiquei à tarde e realmente funcionou.
A professora Mengmeng é realmente incrível.

1. Precisamos importar a biblioteca de tempo da biblioteca pandas
2. Configure o contrato trimestral na função principal (principalmente executando OKEX)
3. Defina um loop doTicker() para testar uma vez a cada 15 minutos.
Execute o código em um ciclo de 15 minutos
Em seguida, 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)

4. Precisamos recuperar o OHCLV da linha K, então use GetRecords()
5. Importamos os dados recuperados para o pandas M15 = pd.DataFrame(records)
6. Precisamos modificar a tag do cabeçalho da tabela. M15.colunas =['time','open','high','low','close','volume','OpenInterest']
Na verdade, ele apenas muda as primeiras letras de "open", "high", "low" e "close" para minúsculas, para que seja mais fácil escrever código mais tarde sem alternar entre maiúsculas e minúsculas.

def doTicker(records): M15 = pd.DataFrame(records) M15.columns = ['time','open','high','low','close','volume','OpenInterest']

7. Adicione uma coluna hl2 ao conjunto de dados hl2=(high+low)/2

#HL2 M15['hl2']=(M15['high']+M15['low'])/2

8. Em seguida, vamos calcular o ATR
Como o cálculo do ATR requer a importação de um comprimento variável, seu valor é Pd

Em seguida, nos referimos ao manual da linguagem Mai, e as etapas do algoritmo da média de volatilidade verdadeira do ATR são as seguintes:
TR : MAX(MAX((HIGH-LOW),ABS(REF(CLOSE,1)-HIGH)),ABS(REF(CLOSE,1)-LOW));
ATR : RMA(TR,N)

O valor TR é a maior das três diferenças a seguir.

  1. A flutuação entre o preço mais alto e o preço mais baixo do dia de negociação atual MÁXIMA-MÍNIMA
  2. A flutuação entre o preço de fechamento do dia de negociação anterior e o preço mais alto do dia de negociação atual (REF(CLOSE,1)-HIGH)
  3. A flutuação entre o preço de fechamento do dia de negociação anterior e o preço mais baixo do dia de negociação atual (REF(CLOSE,1)-LOW)
    Então TR: MAX(MAX((ALTO-BAIXO),ABS(REF(FECHAR,1)-ALTO)),ABS(REF(FECHAR,1)-BAIXO));

Em cálculos Python

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

Primeiro, configure um prev_close para obter os dados de close na linha anterior, ou seja, mova close para a direita em 1 grade para formar um novo parâmetro

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

Em seguida, defina uma variável intermediária para registrar a matriz de três valores de comparação de TR. (ALTO-BAIXO)(alto-anterior_fechamento)(baixo-anterior_fechamento)

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

Definimos uma nova coluna chamada TR no conjunto de dados. O valor de TR é o valor absoluto máximo da variável intermediária. Usamos 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()

Por fim, precisamos calcular o valor de ATR, ATR:RMA (TR, N). Descobriu-se que o algoritmo RMA é, na verdade, uma variante de valor fixo do algoritmo EMA.
N é a variável que importamos, onde o parâmetro padrão para ATR é 14. Aqui importamos alfa = o recíproco do comprimento.

===

Em seguida, use o algoritmo EWM para calcular a 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 Comece a calcular Up e Dn

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

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

O seguinte é o segmento de código principal das linhas 15-21 na 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 objetivo principal deste parágrafo é expressar,
Se em uma fase de alta, (linha inferior) TrendUp = max(Up,TrendUp[1])
Se estiver em fase de queda, (linha superior) TrendDown=min(Dn,TrendDown[1])
Ou seja, em uma tendência, o valor do ATR vem utilizando uma técnica similar à estratégia Bandit Bollinger.
Continue estreitando o outro lado do canal

Aqui, cada cálculo de TrendUp e TrendDown precisa ser autoiterado.
Ou seja, cada passo deve ser calculado com base no passo anterior.
Então precisamos percorrer o conjunto de dados.

Aqui, primeiro precisamos criar novos campos TrendUp, TrendDown, Trend e linecolor para o conjunto de dados. E dê a eles um valor inicial
Em seguida, use a sintaxe fillna(0) para preencher os dados com valores nulos nos resultados calculados 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)

Iniciar um loop for
Usando operações ternárias do Python em loops

for x in range(len(M15)):

Calculando TrendUp
TrendUp = MAX(Up,TrendUp[-1]) if close[-1]>TrendUp[-1] else Up
O significado geral é que se o fechamento anterior > o TrendUp anterior, se for verdadeiro, pegue o valor máximo de Up e o TrendUp anterior, se não for verdadeiro, pegue o valor Up e passe 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 TrendDown
TrendDown=min(Dn,TrendDown[-1]) if close[-1]<TrendDown[-1] else Dn
O significado geral é que se o fechamento anterior < o TrendDown anterior, se for verdadeiro, pegue o valor mínimo entre Dn e o TrendDown anterior, se não for verdadeiro, pegue o valor Dn e passe para o TrendDown atual

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]

Abaixo está o sinalizador para calcular a direção do controle. Simplifiquei o pseudocódigo
Trend= 1 if (close > TrendDown[-1]) else (x)
x = -1 if (close< TrendUp[-1]) else Trend[-1]

O significado é que se o preço de fechamento > o TrendDown anterior, então pegue 1 (altista), caso contrário, pegue x
Se o preço de fechamento for menor que o TrendUp anterior, então tome -1 (curto). Se não, tome o Trend anterior (o que significa que ele permanece inalterado).
Traduzido em linguagem gráfica, significa romper o trilho superior para mudar a bandeira para alta, romper o trilho inferior para mudar a bandeira para baixa, e os outros tempos permanecem inalterados.

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

Calcular Tsl e Linecolor
Tsl= rendUp if (Trend==1) else TrendDown
Tsl é usado para representar o valor do SuperTrend no gráfico. Isso significa que quando você estiver otimista, marque a faixa inferior no gráfico, e quando estiver pessimista, marque a faixa superior no gráfico.
linecolor= 'green' if (Trend==1) else 'red'
O significado de linecolor é se você estiver otimista, marque a linha verde, se estiver pessimista, marque a cor vazia (usado principalmente para exibição do Tradingview)

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 linhas 23 a 30 a seguir são principalmente para plotagem, o que não será explicado em detalhes aqui.

Por fim, existem 2 linhas de código para controle de sinal de compra e venda
No Tradingview, significa dar um sinal após reverter a Bandeira.
Converta instruções condicionais para python.
Se a bandeira de tendência anterior mudar de -1 para 1, significa que a resistência superior foi quebrada. Abra longo
Se a bandeira de tendência anterior mudar de 1 para -1, significa que o suporte descendente foi quebrado. Abra uma posição curta.

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 para esta seção é 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

5. Todos os códigos

Ajustei a estrutura geral do código.
E mescle as instruções de ordens longas e curtas relacionadas à 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);

Link de estratégia pública: https://www.fmz.com/strategy/200625

6. Backtesting e Resumo

Selecionamos dados do ano passado para backtesting.
Use o contrato trimestral da OKEX com um ciclo de 15 minutos.
Os parâmetros definidos são,
Factor=3
Pd=45
vol=100 (100 ingressos por pedido)
O retorno anualizado é de aproximadamente 33%.
Em geral, o recuo não é muito grande.
A principal razão para isso é a falha do 312, que teve um impacto significativo no sistema.
Se não houvesse 312, os retornos seriam melhores.

img

6. Considerações finais

SuperTrend é um sistema de negociação muito bom

O princípio principal do sistema SuperTrend é usar a estratégia de rompimento do canal ATR (semelhante ao canal Kent)
Mas a principal mudança está no uso da estratégia de estreitamento de Bandit Bollinger, ou princípio Donchian reverso.
Os canais superior e inferior estão constantemente se estreitando durante a operação de mercado.
Para conseguir a operação de avanço e rotação do canal. (Uma vez rompido o canal, os trilhos superiores e inferiores retornam aos seus valores iniciais)

Eu tracei o TrendUp TrendDn separadamente no TradingView
Isso ajudará você a entender melhor essa estratégia

Claro num piscar de olhos
img

Há também uma versão js no github. Não entendo muito bem de js, mas a julgar pela instrução if, parece haver algum problema.
O endereço éhttps://github.com/Dodo33/gekko-supertrend-strategy/blob/master/Supertrend.js

Finalmente encontrei a versão original.
Foi publicado em 2013.05.29
Escrito por Rajandran R
Código C++ publicado no fórum Mt4https://www.mql5.com/en/code/viewcode/10851/128437/Non_Repainting_SuperTrend.mq4
Eu entendo aproximadamente o significado de C++ e vou reescrevê-lo quando tiver oportunidade.

Espero que todos possam aprender a essência disso.
É difícil. ~!

Related Recommendations
Comment
All comments (25)

    YYDS!

    5 years ago

    如果直接使用这个策略在OK交易所交易需要怎么连接交易所,小白一个不会python,看不明白

    6 years ago

    这里如果312那波行情没吃到的话应该参数还有很大的调整空间,因为supertrend主要就是抓趋势单,312是不应该错过的。另外期待lz的pine翻译器早日问世

    6 years ago

    可惜各种周期和参数,回测效果都不怎么好, 不知道其它人怎么优化的?

    6 years ago

    可以了,弄好了,感谢您的付出

    6 years ago

    用不了呢,显示这个:Traceback (most recent call last): File "<string>", line 1473, in Run File "<string>", line 8, in <module> ImportError: No module named pandas

    6 years ago

    意思是缺少pandas包 你的系统可能需要pip install pandas

    6 years ago

    请问这是怎么处理的呢?万分感谢

    6 years ago

    pine的翻译器,期待

    6 years ago

    没啥文化只能说一声 牛逼!

    6 years ago

    “估摸着某一天写一个pine的翻译器。一切皆可python。”—— 牛,好些人看好这个!

    6 years ago

    啊哈哈,谢谢老板

    6 years ago

    期待期待,pine真的看不太懂,教程也很少

    6 years ago

    回测引擎的代码是否可以开源呢,我想实现复现一下 然后用svm找出最好的参数

    6 years ago

    这个系统好像也曾经是收益率前十的期货策略。长期坚持做下去是能赚钱的。

    6 years ago

    恩啊。学习精髓。

    6 years ago

    你好,请教下,PD就是 ATR的长度值吧? 比如 ATR(14) ,就是 PD赋值14了吧?

    6 years ago

    是的,完全正确

    6 years ago

    好的,谢谢!!!
    顺手mq4也收走了,谢谢。。 o(∩_∩)o

    6 years ago

    感谢梦梦老师哈

    6 years ago

    碰巧我也写了个JS版本的。

    6 years ago

    求JS版!

    6 years ago

    一会儿,公开。

    6 years ago

    赞的,!

    6 years ago
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)