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

img

1. Origine de l'histoire

Mon bon ami Ran observe cet indicateur depuis longtemps et me l'a recommandé avant le jour de l'An pour discuter s'il peut être converti sous une forme quantitative.
Malheureusement, j'ai souffert de procrastination et je ne l'ai pas aidé à réaliser son souhait jusqu'à présent. En fait, ma compréhension des algorithmes a fait de grands progrès récemment.
J'ai l'intention d'écrire un traducteur de pins un jour. Tout peut être python. .
Bon, sans plus tarder, laissez-nous vous présenter cette ligne légendaire et super tendance. .

2. Présentation du système

La nouvelle génération du système de trading intelligent de CMC Markets - Supertrend
Voici un article présentant ce système.
img

Dans la nouvelle génération de système de trading intelligent de CMC Markets, sélectionnez « Super Trend Line » dans les indicateurs techniques pour l'appeler.
Comme le montre la figure, vous pouvez ajuster la « couleur et l'épaisseur » des signaux montants et descendants selon vos préférences.
Alors, qu’est-ce que l’indicateur de supertendance ? Avant de comprendre la formule de l'indicateur supertrend, il est nécessaire de comprendre l'ATR car supertrend utilise les valeurs ATR pour calculer les valeurs de l'indicateur.

L'algorithme principal est également présenté dans une image ci-dessous.
img

À première vue, la description principale est un canal de HL2 (prix moyen de la ligne K) multiplié par n fois ATR. Réalisez une percée dans les tendances.
Mais l’article est plutôt bref. Il n'y a pas d'algorithme détaillé. Ensuite, j'ai pensé à la meilleure communauté Tradingview.
Pas surprenant. Effectivement, il est là.
img

À en juger par le graphique, cela correspond tout à fait à la tendance. Mais malheureusement, ce n’est qu’un signal d’alerte.

3. Étudiez le code source

Le code ne semble pas trop long, alors traduisons-le et essayons-le. ! (っ•̀ω•́)っ✎⁾⁾!
img
Le code pin complet est le même que ci-dessus. .

4. Conversion de code

Ici, nous créons une nouvelle stratégie dans FMZ et la nommons SuperTrade
img

Ensuite, nous définissons deux paramètres Factor et Pd
img

Afin de mieux simplifier le fonctionnement du code et de le rendre plus facile à comprendre, nous devons utiliser le package d'extension de données avancé de Pythonpandas

Pendant le déjeuner, j'ai demandé au professeur Mengmeng si FMZ soutenait cette bibliothèque. Je l'ai vérifié dans l'après-midi et cela fonctionnait réellement.
Le professeur Mengmeng est vraiment incroyable.

1. Nous devons importer la bibliothèque pandas time library
2. Configurer le contrat trimestriel dans la fonction principale (principalement en exécutant OKEX)
3. Définissez une boucle doTicker() pour tester une fois toutes les 15 minutes.
Exécutez le code sur un cycle de 15 minutes
Ensuite, nous écrivons la stratégie principale dans 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. Nous devons récupérer l'OHCLV de la ligne K, donc utilisez GetRecords()
5. Nous importons les données récupérées dans pandas M15 = pd.DataFrame(records)
6. Nous devons modifier la balise d’en-tête du tableau. M15.colonnes =['time','open','high','low','close','volume','OpenInterest']
En fait, il change simplement les premières lettres de « ouvert », « haut », « bas » et « proche » en minuscules, de sorte qu'il est plus facile d'écrire du code plus tard sans alterner entre majuscules et minuscules.

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

7. Ajoutez une colonne hl2 à l'ensemble de données hl2=(high+low)/2

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

8. Ensuite, calculons l’ATR
Étant donné que le calcul de l'ATR nécessite l'importation d'une longueur variable, sa valeur est Pd

Ensuite, nous nous référons au manuel de langue Mai, et les étapes de l'algorithme de la moyenne de volatilité réelle ATR sont les suivantes :
TR : MAX(MAX((HIGH-LOW),ABS(REF(CLOSE,1)-HIGH)),ABS(REF(CLOSE,1)-LOW));
ATR : RMA(TR,N)

La valeur TR est la plus grande des trois différences suivantes.

  1. La fluctuation entre le prix le plus élevé et le prix le plus bas de la journée de négociation en cours HAUT-BAS
  2. La fluctuation entre le cours de clôture du jour de négociation précédent et le cours le plus élevé du jour de négociation en cours (REF(CLOSE,1)-HIGH)
  3. La fluctuation entre le cours de clôture du jour de négociation précédent et le cours le plus bas du jour de négociation en cours (REF(CLOSE,1)-LOW)
    Donc TR : MAX(MAX((HAUT-BAS),ABS(REF(FERMETURE,1)-HAUT)),ABS(REF(FERMETURE,1)-BAS));

Dans les calculs Python

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

Tout d'abord, configurez un prev_close pour obtenir les données de close dans la ligne précédente, c'est-à-dire, déplacez close vers la droite d'une grille pour former un nouveau paramètre

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

Ensuite, définissez une variable intermédiaire pour enregistrer le tableau de trois valeurs de comparaison de TR. (HAUT-BAS)(haut-précédent_fermer)(bas-précédent_fermer)

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

Nous définissons une nouvelle colonne nommée TR dans l'ensemble de données. La valeur de TR est la valeur absolue maximale de la variable intermédiaire. Nous utilisons les fonctions abs() et max().

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

Enfin, nous devons calculer la valeur de ATR, ATR: RMA (TR, N). Il s'avère que l'algorithme RMA est en fait une variante à valeur fixe de l'algorithme EMA.
N est la variable que nous avons importée, où le paramètre par défaut pour ATR est 14. Ici, nous importons alpha = l'inverse de la longueur.

===

Utilisez ensuite l'algorithme EWM pour calculer l'EMA
Le processus complet de calcul de l'ATR est le suivant

#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 Commencez à calculer Up et Dn

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

Up=hl2 -(Factor * atr)
Dn=hl2 +(Factor * atr)
N’est-ce pas simple ?

Ce qui suit est le segment de code principal des lignes 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

Le but principal de ce paragraphe est d’exprimer,
Si dans une phase haussière, (ligne inférieure) TrendUp = max(Up,TrendUp[1])
S'il est en phase de baisse, (ligne supérieure) TrendDown=min(Dn,TrendDown[1])
Autrement dit, dans une tendance, la valeur ATR a utilisé une technique similaire à la stratégie Bandit Bollinger.
Continuez à rétrécir l'autre côté du canal

Ici, chaque calcul de TrendUp et TrendDown doit être auto-itéré.
Autrement dit, chaque étape doit être calculée en fonction de l’étape précédente.
Nous devons donc parcourir l’ensemble de données.

Ici, nous devons d’abord créer de nouveaux champs TrendUp, TrendDown, Trend et linecolor pour l’ensemble de données. Et donnez-leur une valeur initiale
Utilisez ensuite la syntaxe fillna(0) pour remplir les données avec des valeurs nulles dans les résultats précédemment calculés avec 0

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

Démarrer une boucle for
Utilisation des opérations ternaires Python dans les boucles

for x in range(len(M15)):

Calcul de TrendUp
TrendUp = MAX(Up,TrendUp[-1]) if close[-1]>TrendUp[-1] else Up
La signification générale est que si la clôture précédente > le TrendUp précédent, si c'est vrai, prendre la valeur maximale de Up et du TrendUp précédent, si ce n'est pas vrai, prendre la valeur Up et la transmettre au TrendUp actuel

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]

De même, calculez TrendDown
TrendDown=min(Dn,TrendDown[-1]) if close[-1]<TrendDown[-1] else Dn
La signification générale est que si la clôture précédente < la tendance baissière précédente, si c'est vrai, prendre la valeur minimale entre Dn et la tendance baissière précédente, si ce n'est pas vrai, prendre la valeur Dn et la passer à la tendance baissière actuelle

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]

Ci-dessous se trouve le drapeau permettant de calculer la direction de contrôle. J'ai simplifié le pseudo-code
Trend= 1 if (close > TrendDown[-1]) else (x)
x = -1 if (close< TrendUp[-1]) else Trend[-1]

La signification est que si le prix de clôture > le TrendDown précédent, alors prenez 1 (haussier) sinon, prenez x
Si le cours de clôture est inférieur au TrendUp précédent, prenez -1 (short). Sinon, prenez le Trend précédent (ce qui signifie qu'il reste inchangé).
Traduit en langage graphique, cela signifie franchir le rail supérieur pour faire passer le drapeau à la hausse, franchir le rail inférieur pour faire passer le drapeau à la baisse, et les autres temps restent inchangés.

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

Calculer Tsl et Linecolor
Tsl= rendUp if (Trend==1) else TrendDown
Tsl est utilisé pour représenter la valeur de SuperTrend sur le graphique. Cela signifie que lorsque vous êtes haussier, marquez la piste inférieure sur le graphique, et lorsque vous êtes baissier, marquez la piste supérieure sur le graphique.
linecolor= 'green' if (Trend==1) else 'red'
La signification de linecolor est que si vous êtes haussier, marquez la ligne verte, si vous êtes baissier, marquez la couleur vide (principalement utilisée pour l'affichage 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'

Les lignes 23 à 30 suivantes sont principalement destinées au traçage, qui ne sera pas expliqué en détail ici.

Enfin, il y a 2 lignes de code pour le contrôle des signaux d'achat et de vente
Dans Tradingview, cela signifie donner un signal après avoir inversé le drapeau.
Convertissez les instructions conditionnelles en Python.
Si le drapeau de tendance précédent passe de -1 à 1, cela signifie que la résistance supérieure a été cassée. Ouvrir long
Si le drapeau de tendance précédent passe de 1 à -1, cela signifie que le support a été cassé. Ouvrez une position courte.

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)

Le code complet de cette section est le suivant :

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. Tous les codes

J'ai ajusté la structure globale du code.
Et fusionnez les instructions d’ordre longues et courtes dans la stratégie.
Voici le code complet

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

Lien vers la stratégie publique : https://www.fmz.com/strategy/200625

6. Backtesting et résumé

Nous avons sélectionné des données de l’année écoulée pour effectuer des tests rétrospectifs.
Utilisez le contrat trimestriel OKEX avec un cycle de 15 minutes.
Les paramètres définis sont,
Factor=3
Pd=45
vol=100 (100 billets par commande)
Le rendement annualisé est d’environ 33 %.
En général, le retracement n’est pas très important.
La principale raison en est le crash du 312 qui a eu un impact significatif sur le système.
S'il n'y avait pas de 312, les rendements seraient meilleurs.

img

6. Réflexions finales

SuperTrend est un très bon système de trading

Le principe principal du système SuperTrend est d'utiliser la stratégie de rupture du canal ATR (similaire au canal Kent)
Mais le principal changement réside dans l’utilisation de la stratégie de rétrécissement Bandit Bollinger, ou du principe Donchian inversé.
Les canaux supérieur et inférieur se rétrécissent constamment pendant le fonctionnement du marché.
Afin de réaliser la percée du canal et l'opération de tournage. (Une fois le canal franchi, les rails supérieur et inférieur reviennent à leurs valeurs initiales)

J'ai tracé TrendUp et TrendDn séparément sur TradingView
Cela vous aidera à mieux comprendre cette stratégie

Clair en un coup d'oeil
img

Il existe également une version js sur github. Je ne comprends pas très bien le js, mais à en juger par l'instruction if, il semble y avoir un problème.
L'adresse esthttps://github.com/Dodo33/gekko-supertrend-strategy/blob/master/Supertrend.js

J'ai finalement retrouvé la version originale.
Il a été publié le 29/05/2013
Écrit par Rajandran R
Code C++ publié sur le forum Mt4https://www.mql5.com/en/code/viewcode/10851/128437/Non_Repainting_SuperTrend.mq4
Je comprends à peu près la signification de C++ et je le réécrirai quand j'en aurai l'occasion.

J’espère que tout le monde pourra en tirer l’essentiel.
Il est difficile. ~!

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)