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.
In der neuen Generation des intelligenten Handelssystems in CMC Markets können wir
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.
Wenn man sich das Diagramm anschaut, ist es im Einklang mit dem Trend. Leider ist es nur ein Alarmsignal von Alert.
Der Code ist nicht zu lang, also versuchen wir ihn zu übersetzen.!(っ•̀ω•́)っ
Der vollständige Pine-Code ist wie oben.
Hier erstellen wir eine neue Strategie auf FMZ, nennen es SuperTrend
Als nächstes setzen wir zwei Parameter, Faktor und Pd
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.
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):
M15 = pd.DataFrame(records)
M15.columns = ['time','open','high','low','close','volume','OpenInterest']
#HL2
M15['hl2']=(M15['high']+M15['low'])/2
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:
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=
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)
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
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.
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:
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.