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

img

1. Ursprung der Geschichte

Mein guter Freund Ran beobachtet diesen Indikator schon lange und hat ihn mir vor Neujahr empfohlen, um zu besprechen, ob er in eine quantitative Form umgewandelt werden kann.
Leider habe ich unter Prokrastination gelitten und ihm bis jetzt nicht dabei geholfen, seinen Wunsch zu erfüllen. Tatsächlich habe ich in letzter Zeit große Fortschritte in meinem Verständnis von Algorithmen gemacht.
Ich habe vor, eines Tages einen Pine-Übersetzer zu schreiben. Alles kann Python sein. .
Okay, ohne weitere Umschweife möchten wir Ihnen diese legendäre Supertrendlinie vorstellen. .

2. Systemeinführung

Die neue Generation intelligenter Handelssysteme von CMC Markets - Supertrend
Hier ist ein Artikel, der dieses System vorstellt.
img

Wählen Sie in der neuen Generation intelligenter Handelssysteme von CMC Markets „Super Trend Line“ in den technischen Indikatoren aus, um es aufzurufen.
Wie in der Abbildung gezeigt, können Sie die „Farbe und Dicke“ der steigenden und fallenden Signale nach Ihren Wünschen anpassen.
Was also ist der Supertrendindikator? Bevor man die Formel des Supertrend-Indikators versteht, muss man ATR verstehen, da Supertrend ATR-Werte zur Berechnung der Indikatorwerte verwendet.

Der Hauptalgorithmus wird auch im Bild unten vorgestellt.
img

Auf den ersten Blick ist die Hauptbeschreibung ein Kanal von HL2 (Durchschnittspreis der K-Linie) multipliziert mit n-mal ATR. Machen Sie einen Trendausbruch.
Der Artikel ist jedoch ziemlich kurz. Es gibt keinen detaillierten Algorithmus. Dann dachte ich an die beste Community Tradingview.
Kein Wunder. Und tatsächlich, es ist da.
img

Der Grafik zufolge entspricht es durchaus dem Trend. Aber leider ist es nur ein Warnsignal.

3. Studieren Sie den Quellcode

Der Code sieht nicht zu lang aus, also übersetzen wir ihn und probieren es aus. ! (っ•̀ω•́)っ✎⁾⁾!
img
Der vollständige Pine-Code ist wie oben. .

4. Code-Konvertierung

Hier erstellen wir eine neue Strategie in FMZ und nennen sie SuperTrade
img

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

Um die Funktionsweise des Codes zu vereinfachen und verständlicher zu machen, müssen wir das erweiterte Datenerweiterungspaket von Python verwendenpandas

Während des Mittagessens fragte ich Lehrerin Mengmeng, ob die FMZ diese Bibliothek unterstützt. Ich habe es am Nachmittag überprüft und es hat tatsächlich funktioniert.
Lehrer Mengmeng ist wirklich unglaublich.

1. Wir müssen die Pandas-Bibliothek Zeitbibliothek importieren
2. Richten Sie den Quartalsvertrag in der Hauptfunktion ein (hauptsächlich OKEX ausführen)
3. Richten Sie eine doTicker()-Schleife ein, um alle 15 Minuten einen Test durchzuführen.
Führen Sie den Code im 15-Minuten-Zyklus aus
Als nächstes 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)

4. Wir müssen den OHCLV der K-Linie abrufen, also verwenden wir GetRecords()
5. Wir importieren die abgerufenen Daten in Pandas M15 = pd.DataFrame(Datensätze)
6. Wir müssen das Tabellenkopf-Tag ändern. M15.Spalten =['time','open','high','low','close','volume','OpenInterest']
Tatsächlich werden dabei nur die Anfangsbuchstaben von „open“, „high“, „low“ und „close“ in Kleinbuchstaben geändert, damit sich später Code leichter schreiben lässt, ohne zwischen Groß- und Kleinschreibung wechseln zu müssen.

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

7. Fügen Sie dem Datensatz hl2=(high+low)/2 eine Spalte hl2 hinzu

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

8. Als nächstes berechnen wir den ATR
Da die Berechnung von ATR den Import einer variablen Länge erfordert, ist ihr Wert Pd

Dann verweisen wir auf das Mai-Sprachhandbuch, und die Algorithmusschritte des ATR-Durchschnitts der wahren Volatilität lauten 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 der größte der folgenden drei Unterschiede.

  1. Die Schwankung zwischen dem Höchstkurs und dem Tiefstkurs des aktuellen Handelstages HIGH-LOW
  2. Die Schwankung zwischen dem Schlusskurs des vorherigen Handelstages und dem Höchstkurs des aktuellen Handelstages (REF(CLOSE,1)-HIGH)
  3. Die Schwankung zwischen dem Schlusskurs des vorherigen Handelstages und dem niedrigsten Kurs des aktuellen Handelstages (REF(CLOSE,1)-LOW)
    Also TR: MAX(MAX((HOCH-NIEDRIG),ABS(REF(SCHLUSS,1)-HOCH)),ABS(REF(SCHLUSS,1)-NIEDRIG));

In Python-Berechnungen

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

Richten Sie zunächst ein prev_close ein, um die Daten von close in der vorherigen Zeile abzurufen, d. h., verschieben Sie close um 1 Raster nach rechts, um einen neuen Parameter zu bilden

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

Definieren Sie als Nächstes eine Zwischenvariable, um das Array der drei Vergleichswerte von TR aufzuzeichnen. (HOCH-NIEDRIG)(hoch-vorherig_schließen)(niedrig-vorherig_schließen)

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

Wir definieren eine neue Spalte namens TR im Datensatz. Der Wert von TR ist der maximale absolute Wert der Zwischenvariable. Wir verwenden die 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 berechnen, ATR: RMA (TR, N). Es stellt sich heraus, dass der RMA-Algorithmus tatsächlich eine Festwertvariante des EMA-Algorithmus ist.
N ist die von uns importierte Variable, wobei der Standardparameter für ATR 14 ist. Hier importieren wir Alpha = den Kehrwert der Länge.

===

Verwenden Sie dann den EWM-Algorithmus zur Berechnung des EMA
Der vollständige ATR-Berechnungsprozess läuft wie folgt ab

#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 Beginnen Sie mit der Berechnung von Up und Dn

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

Up=hl2 -(Factor * atr)
Dn=hl2 +(Factor * atr)
Ist es nicht einfach?

Nachfolgend sehen Sie den Kerncodeabschnitt der Zeilen 15-21 in 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 Hauptzweck dieses Absatzes besteht darin, auszudrücken,
Wenn in einer bullischen Phase, (untere Linie) TrendUp = max(Up,TrendUp[1])
Wenn es sich in der fallenden Phase befindet (obere Linie), TrendDown=min(Dn,TrendDown[1])
Das heißt, in einem Trend hat der ATR-Wert eine Technik verwendet, die der Bandit-Bollinger-Strategie ähnelt.
Verengen Sie die andere Seite des Kanals weiter

Hier muss jede Berechnung von TrendUp und TrendDown selbst iteriert werden.
Das heißt, jeder Schritt muss auf Grundlage des vorherigen Schritts berechnet werden.
Wir müssen also den Datensatz durchlaufen.

Hier müssen wir zunächst die neuen Felder TrendUp, TrendDown, Trend und Linienfarbe für den Datensatz erstellen. Und geben Sie ihnen einen Anfangswert
Verwenden Sie dann die Syntax fillna(0), um die Daten mit Nullwerten in den zuvor berechneten Ergebnissen 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)

Starten Sie eine For-Schleife
Verwenden ternärer Python-Operationen in Schleifen

for x in range(len(M15)):

TrendUp berechnen
TrendUp = MAX(Up,TrendUp[-1]) if close[-1]>TrendUp[-1] else Up
Die allgemeine Bedeutung ist: Wenn der vorherige Schlusswert > der vorherige TrendUp ist, wird, wenn dies zutrifft, der Maximalwert von Up und dem vorherigen TrendUp genommen, wenn dies nicht zutrifft, wird der Up-Wert genommen und an den aktuellen TrendUp übergeben

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]

Berechnen Sie in ähnlicher Weise TrendDown
TrendDown=min(Dn,TrendDown[-1]) if close[-1]<TrendDown[-1] else Dn
Die allgemeine Bedeutung ist, dass, wenn der vorherige Schlusswert < der vorherige TrendDown ist, wenn dies zutrifft, der Mindestwert zwischen Dn und dem vorherigen TrendDown genommen wird, wenn dies nicht zutrifft, der Dn-Wert genommen und an den aktuellen TrendDown übergeben wird

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]

Unten ist das Flag zur Berechnung der Steuerrichtung. Ich habe den Pseudocode vereinfacht
Trend= 1 if (close > TrendDown[-1]) else (x)
x = -1 if (close< TrendUp[-1]) else Trend[-1]

Die Bedeutung ist, dass wenn der Schlusskurs > dem vorherigen TrendDown ist, dann 1 (bullisch) genommen wird, wenn nicht, dann x genommen wird.
Wenn der Schlusskurs unter dem vorherigen TrendUp liegt, nehmen Sie -1 (Short). Wenn nicht, nehmen Sie den vorherigen Trend (was bedeutet, dass er unverändert bleibt).
Grafisch übersetzt bedeutet dies, dass ein Durchbrechen der oberen Schiene die Flagge auf bullisch umstellt, ein Durchbrechen der unteren Schiene die Flagge auf bärisch umstellt und die übrigen Zeitpunkte unverändert bleiben.

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

TSL und Linienfarbe berechnen
Tsl= rendUp if (Trend==1) else TrendDown
Tsl wird verwendet, um den Wert von SuperTrend im Diagramm darzustellen. Dies bedeutet: Wenn Sie optimistisch sind, markieren Sie die untere Spur im Diagramm, und wenn Sie pessimistisch sind, markieren Sie die obere Spur im Diagramm.
linecolor= 'green' if (Trend==1) else 'red'
Die Bedeutung der Linienfarbe ist: Wenn Sie bullisch sind, markieren Sie die grüne Linie, wenn Sie bearisch sind, markieren Sie die leere Farbe (hauptsächlich für die Tradingview-Anzeige verwendet)

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 folgenden Zeilen 23-30 dienen hauptsächlich dem Plotten und werden hier nicht näher erläutert.

Schließlich gibt es noch 2 Codezeilen für die Kauf- und Verkaufssignalsteuerung
In Tradingview bedeutet dies, nach dem Umkehren der Flagge ein Signal zu geben.
Konvertieren Sie bedingte Anweisungen in Python.
Wenn sich das vorherige Trend-Flag von -1 auf 1 ändert, bedeutet dies, dass der obere Widerstand durchbrochen wurde. Öffnen Sie eine Long-Position.
Wenn sich die vorherige Trendflagge von 1 auf -1 ändert, bedeutet dies, dass die Abwärtsunterstützung durchbrochen wurde. Eröffnen Sie eine Short-Position.

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 für diesen Abschnitt 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

5. Alle Codes

Ich habe die gesamte Codestruktur angepasst.
Und integrieren Sie die Long- und Short-Order-Anweisungen in die Strategie.
Hier ist der komplette 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);

Öffentlicher Strategielink: https://www.fmz.com/strategy/200625

6. Backtesting und Zusammenfassung

Für das Backtesting haben wir Daten aus dem vergangenen Jahr ausgewählt.
Verwenden Sie den OKEX-Quartalsvertrag mit einem 15-Minuten-Zyklus.
Die festgelegten Parameter sind:
Factor=3
Pd=45
vol=100 (100 Tickets pro Bestellung)
Die annualisierte Rendite beträgt ca. 33 %.
Im Allgemeinen ist die Korrektur nicht sehr groß.
Der Hauptgrund hierfür ist der Absturz der 312, der erhebliche Auswirkungen auf das System hatte.
Wenn es die Nummer 312 nicht gäbe, wäre die Rendite besser.

img

6. Abschließende Gedanken

SuperTrend ist ein sehr gutes Handelssystem

Das Hauptprinzip des SuperTrend-Systems besteht in der Verwendung der ATR-Kanal-Ausbruchsstrategie (ähnlich dem Kent-Kanal).
Die wichtigste Änderung liegt jedoch in der Verwendung der Bandit-Bollinger-Verengungsstrategie bzw. des umgekehrten Donchian-Prinzips.
Die oberen und unteren Kanäle verengen sich während der Marktoperation ständig.
Um den Kanaldurchbruch und die Drehoperation zu erreichen. (Sobald der Kanal durchbricht, kehren die oberen und unteren Schienen zu ihren Anfangswerten zurück)

Ich habe dn TrendUp TrendDn separat auf TradingView dargestellt
Dies wird Ihnen helfen, diese Strategie besser zu verstehen

Übersichtlich auf einen Blick
img

Es gibt auch eine JS-Version auf GitHub. Ich verstehe nicht viel von JS, aber der if-Anweisung nach zu urteilen, scheint es da ein Problem zu geben.
Die Adresse lautethttps://github.com/Dodo33/gekko-supertrend-strategy/blob/master/Supertrend.js

Endlich habe ich die Originalversion gefunden.
Es wurde am 29.05.2013 veröffentlicht
Geschrieben von Rajandran R
C++-Code im Mt4-Forum veröffentlichthttps://www.mql5.com/en/code/viewcode/10851/128437/Non_Repainting_SuperTrend.mq4
Ich verstehe die Bedeutung von C++ im Großen und Ganzen und werde es neu schreiben, wenn ich die Gelegenheit dazu habe.

Ich hoffe, dass jeder das Wesentliche daraus lernen kann.
Es ist schwierig. ~!

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)