
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. .
La nouvelle génération du système de trading intelligent de CMC Markets - Supertrend
Voici un article présentant ce système.

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.

À 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à.

À en juger par le graphique, cela correspond tout à fait à la tendance. Mais malheureusement, ce n’est qu’un signal d’alerte.
Le code ne semble pas trop long, alors traduisons-le et essayons-le. ! (っ•̀ω•́)っ✎⁾⁾!
Le code pin complet est le même que ci-dessus. .
Ici, nous créons une nouvelle stratégie dans FMZ et la nommons SuperTrade

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

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]
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)


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
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.

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

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. ~!