SuperTrend V.1 -- Super Trendlinie-System

Schriftsteller:Lydia., Erstellt: 2022-12-01 11:36:33, Aktualisiert: 2023-09-11 20:04:38

img

I. Ursprung der Geschichte

Herr Ran, mein guter Freund, hat diesen Indikator schon lange beobachtet und mir vor dem Neujahrstag empfohlen, darüber zu diskutieren, ob er in Quantifizierung umgewandelt werden kann. Es ist schade, dass der Aufschieber sich bis jetzt aufgehalten hat, ihm zu helfen, einen solchen Wunsch zu erfüllen. Es wird geschätzt, dass ich eines Tages einen Übersetzer für die Pine Sprache schreiben werde. Alles kann Python sein. Nun, ohne viel Unsinn, lassen Sie uns die legendäre Super-Trend-Linie vorstellen.

II. Einführung des Systems

In der neuen Generation des intelligenten Handelssystems in CMC Markets können wir Super Trend Line aus den zu verwendenden technischen Indikatoren auswählen, Wir können die Farbe und Dicke der zunehmenden und abnehmenden Signale nach unseren Vorlieben anpassen. Vor dem Verständnis der Super Trend Indikator Formel, ist es notwendig, die ATR zu verstehen, weil der Super Trend den ATR Wert anwendet, um den Indikatorwert zu berechnen. Die wichtigsten Algorithmen sind ebenfalls in der folgenden Abbildung beschrieben:

img

Es beschreibt hauptsächlich den Kanal, wo HL2 (k-Line Durchschnittspreis) plus n mal ATR. Aber der Artikel ist einfach. Kein detaillierter Algorithmus. Dann dachte ich an die erstaunlichste Community, TradingView. Ja, es ist wirklich da.

img

Wenn man sich das Diagramm anschaut, ist es im Einklang mit dem Trend. Leider ist es nur ein Alarmsignal von Alert.

III. Lernen des Quellcodes

Der Code ist nicht zu lang, also versuchen wir ihn zu übersetzen.!(っ•̀ω•́)っ))!

img

Der vollständige Pine-Code ist wie oben.

VI. Codeumwandlung

Hier erstellen wir eine neue Strategie auf FMZ, nennen es SuperTrend

img

Als nächstes setzen wir zwei Parameter, Faktor und Pd

img

Um den Codebetrieb besser zu vereinfachen und das Verständnis zu erleichtern, müssen wir das erweiterte Datenerweiterungspaket Pandas von Python (https://pandas.pydata.org/) FMZ unterstützt diese Bibliothek jetzt.

  1. Wir müssen die Panda-Bibliothek und die Zeitbibliothek importieren.
  2. In der Hauptfunktion wird die Verwendung vierteljährlicher Verträge festgelegt (hauptsächlich für okex)
  3. Setzen Sie einen Zyklus doTicker ((() so ein, dass er alle 15 Minuten erkannt wird. Führen Sie den Code 15 Minuten lang aus. Dann schreiben wir die Hauptstrategie in 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. Wir müssen die OHCLV von K-line abrufen, also benutzen wir GetRecords()
  2. Wir importieren die abgerufenen Daten in Pandas M15 = pd.DataFrame ((Aufzeichnungen)
  3. Wir müssen das Header-Label der Tabelle ändern. M15.Spalten = [zeit,open,high,low,close,volume,OpenInterest] Tatsächlich ist es, die Anfangsbuchstaben von open, high, low und close in Kleinbuchstaben zu ändern, so dass unser späteres Code-Schreiben nicht von Großbuchstaben in Kleinbuchstaben wechseln muss.
def doTicker(records):
    M15 = pd.DataFrame(records)
    M15.columns = ['time','open','high','low','close','volume','OpenInterest']  
  1. Hinzufügen einer Spalte zum Datensatz hl2
#HL2
M15['hl2']=(M15['high']+M15['low'])/2
  1. Dann berechnen wir ATR. Da die ATR-Berechnung eine variable Länge importieren muss, deren Wert Pd ist

Dann verweisen wir auf das Handbuch von MyLanguage, und die Algorithmusschritte des mittleren Wertes der realen ATR-Fluctuationsamplitude sind wie folgt: TR: MAX ((MAX (((HIGH-LOW),ABS ((REF ((CLOSE,1) -HIGH)),ABS ((REF ((CLOSE,1) -LOW)); ATR: RMA(TR,N)

Der TR-Wert ist das Maximum der folgenden drei Unterschiede:

  1. Die Schwankung zwischen dem höchsten und dem niedrigsten Preis am laufenden Handelstag HIGH-LOW
  2. Die Schwankung zwischen dem Schlusskurs des vorherigen Handelstages und dem höchsten Preis des aktuellen Handelstages REF (KLUSSION, 1) - HIGH
  3. Die Schwankung zwischen dem Schlusskurs des vorherigen Handelstages und dem niedrigsten Preis des aktuellen Handelstages REF (KLUSS, 1) - LOW Also TR: MAX(MAX((HIGH-LOW),ABS(REF(CLOSE,1)-HIGH)),ABS(REF(CLOSE,1)-LOW));

Bei der Berechnung von Python

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

Wir müssen ein prev_close einrichten, um die Daten von close in der vorherigen Zeile abzurufen, das heißt, bewegen Sie dicht nach rechts durch ein Raster, um einen neuen Parameter zu bilden

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

Als nächstes definieren wir eine Zwischenvariable, die ein Array von 3 kontrastierenden Werten für TR erfasst. (HIGH-LOW) (high-prev_close) (low-prev_close)

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

Wir definieren eine neue Spalte im Datensatz und benennen sie als TR. Der Wert von TR ist der größte absolute Wert der Zwischenvariablen, mit den Funktionen abs () und max ()

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

Schließlich müssen wir den Wert von ATR, ATR: RMA (TR, N) berechnen. Es stellt sich heraus, dass der RMA-Algorithmus eine Festwertvariante des EMA-Algorithmus ist. N ist die Variable, die wir importieren. Der Standardparameter von ATR ist 14. Hier importieren wir das Gegenteil von alpha = Länge.

===

Dann wird der Ewm-Algorithmus verwendet, um die EMA zu berechnen Der vollständige ATR-Berechnungsvorgang ist wie folgt:

    #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 Berechnen von Up und Dn

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

Auf = hl2 - ((Faktor * atr) Dn=hl2 +(Faktor * atr) Ist das nicht einfach?

Hier ist der Kerncode der Zeilen 15-21 von 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

Der Hauptpunkt dieses Absatzes besteht darin, auszudrücken, daß Wenn es sich in der bullischen Phase befindet (untere Linie) TrendUp=max (Up, TrendUp [1]) Wenn es sich im Fallstadium befindet, (die obere Zeile) TrendDown=min (Dn, TrendDown [1]) Das bedeutet, dass der ATR-Wert in einem Trend eine Technologie verwendet hat, die der Bandit-Bollinger-Strategie ähnelt. Verengern Sie die andere Seite des Kanals.

Hier erfordert jede Berechnung von TrendUp und TrendDown eine Selbstiteration. Das heißt, jeder Schritt sollte nach dem vorhergehenden Schritt berechnet werden. Daher sollte der Datensatz in der Schleife wiederholt werden.

Zuerst erstellen wir neue Felder TrendUp, TrendDown, Trend, Linecolor für den Datensatz. Dann verwenden wir die Grammatik fillna (0) um die Daten mit Nullwert im zuvor berechneten Ergebnis mit 0 zu füllen

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

Aktivieren einer For-Schleife Mit der Python-Ternäroperation in der Schleife

    for x in range(len(M15)):

Berechnen Sie den TrendUp TrendUp = MAX(Up,TrendUp[-1]) wenn nahe[-1]>TrendUp[-1] sonst nach oben Es bedeutet ungefähr, dass, wenn die vorherige Schließung> vorherige TrendUp wahr ist, der maximale Wert zwischen Up und der vorherigen TrendUp genommen wird; wenn nicht, wird der Up-Wert genommen und an die aktuelle TrendUp weitergegeben

        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]

Gleichermaßen berechnen Sie den TrendDown TrendDown=min(Dn,TrendDown[-1]) wenn nahe[-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]

Das Folgende ist die Flagge für die Berechnung der Steuerung Richtung. Ich vereinfachte den Pseudo-Code Trend= 1 wenn (Schließen > TrendDown[-1]) andernfalls (x) x = -1 wenn (nahe< TrendUp[-1]) andernfalls Trend[-1]

Die Bedeutung ist, dass, wenn der Schlusskurs>der vorherige TrendDown, nehmen Sie den Wert von 1 (bullish). Wenn der Schlusskurs kleiner ist als der vorherige TrendUp, nehmen Sie den Wert von -1 (bären). Um es in Bildsprache zu übersetzen, ist das ein Ausbruch der oberen Übergangsflagge für bullish; und ein Ausbruch der unteren Übergangsflagge für bearish.

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

Berechnen Sie Tsl und Linecolor Tsl= RendUp wenn (Trend==1) sonst TrendDown Tsl ist der Wert, der verwendet wird, um den SuperTrend auf dem Bild darzustellen. Es bedeutet, die Abwärtsspur auf dem Bild zu markieren, wenn wir in bullish sind, und die obere Spur auf dem Bild zu markieren, wenn wir in bearish sind. linecolor= grün wenn (Trend==1) andernfalls rot Die Bedeutung von Linecolor ist, die grüne Linie zu markieren, wenn wir in bullish sind, und die leere Farbe zu markieren, wenn wir in bearish sind (hauptsächlich zum Zwecke der Tradeview Anzeige)

        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'

Die nächsten 23-30 Zeilen sind hauptsächlich Plotzeichnungen, die hier nicht erläutert werden.

Schließlich gibt es 2 Zeilen Code, um das Kauf- und Verkaufssignal zu steuern. In Tradeview bedeutet dies, dass das Signal nach dem Umdrehen der Flagge gegeben wird Konvertieren Sie die bedingte Anweisung in Python. Wenn sich die letzte Trend-Flagge von -1 auf 1 ändert, bedeutet dies, dass der obere Widerstand überschritten und die Long-Position geöffnet wurde. Wenn sich die letzte Trendflagge von 1 auf -1 ändert, bedeutet dies, dass die Abwärtsunterstützung überschritten wurde und eine Leerposition eröffnet wurde.

    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)

Der vollständige Code lautet wie folgt:

    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. Vollständiger Code

Ich habe die Gesamtstruktur angepasst. Und ich habe die Anweisungen für den Long- und den Short-Order in die Strategie integriert. Hier ist der vollständige Code:

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

Adresse der öffentlichen Strategie:https://www.fmz.com/strategy/200625

VI. Backtest und Zusammenfassung

Wir wählten die Daten des letzten Jahres für das Backtesting aus. Wir verwenden den OKEX-Quartalsvertrag für einen Zeitraum von 15 Minuten. Die eingestellten Parameter sind: Faktor = 3 Pd=45 Vol=100 (100 Verträge pro Auftrag) Die jährliche Rendite beträgt etwa 33%. Im Allgemeinen ist der Entzug nicht sehr viel, Der starke Rückgang von 312 hatte einen relativ großen Einfluß auf das System. Wenn es keine 312 gibt, sollten die Renditen besser sein.

img

VII. Schreiben Sie am Ende

SuperTrend ist ein sehr gutes Handelssystem.

Das Hauptprinzip des SuperTrend-Systems besteht darin, die ATR-Kanaldurchbruchstrategie (ähnlich dem Kent-Kanal) zu übernehmen Diese Veränderung ist jedoch vor allem auf die Anwendung der Verengungsstrategie des Bandit Bollinger oder auf das Gegenteil des Donchian-Prinzips zurückzuführen. Im Marktbetrieb werden die oberen und unteren Kanäle kontinuierlich verengt. Um den Betrieb der Kanaldurchbrüche zu erreichen. (Sobald der Kanal durchbrochen ist, kehren die oberen und unteren Gleise zum Anfangswert zurück)

Ich zeichne, dn, TrendUp und TrendDn separat auf der TradeView, Das macht es einfacher, die Strategie besser zu verstehen. Sieh es dir auf einen Blick klar:

img

Darüber hinaus gibt es eine Version von js auf Github. Ich bin nicht gut in js, aber es scheint, dass etwas mit der if-Anweisung nicht stimmt. Die Adresse:https://github.com/Dodo33/gekko-supertrend-strategy/blob/master/Supertrend.js

Endlich habe ich die Originalversion gefunden. Veröffentlicht am 29. Mai 2013 Der Autor ist Rajandran R. C++-Code wurde auf dem Mt4-Forum veröffentlicht:https://www.mql5.com/en/code/viewcode/10851/128437/Non_Repainting_SuperTrend.mq4Ich habe grob die Bedeutung von C++ verstanden, und ich werde es neu schreiben, wenn ich die Gelegenheit dazu habe.

Ich hoffe, du kannst die Essenz daraus lernen. Es ist schwierig.


Verwandt

Mehr