Dieses Tutorial zeigt ein fortgeschrittenes Beispiel für Indikatoren, Conditions und Strategien und zeigt dir, wie die einzelnen Scripts miteinander kommunizeren können.
Warum wollen wir das?
AgenaTrader bietet dir die Möglichkeit, Indikatoren, Conditions, Alarme und Strategien in C# zu erstellen und diese während des Trading zu verwenden. Natürlich kann man auch einen Indikator erstellen und danach den Code in eine Condition, Strategie oder Alarm kopieren. Programmierung nach dem „Copy&Paste“ Ansatz ist leicht, bringt aber auch eine Menge Nachteile, wie erschwertes Testen, kompliziertes Bugfixing oder erhöhten Wartungsaufwand, mit sich.
Indikator
In vielen Fällen starten wir mit dem Indikator, da der Indikator der leichteste Einstieg in die Scriptentwicklung ist. Man bekommt einen schnellen Einblick, ob die Tradingidee grundsätzlich funktioniert und zusätzlich kann man schnell und einfach weitere Instrumente visuell screenen und dadurch prüfen, ob die Idee gewinnträchtig wäre.
Result value
Das „ResultValue“-Objekt hält alle Ergebnisse aus der „Calculate“-Methode. Ausgehend von diesen Ergebnissen werden die nächsten Schritte ermittelt. In der Strategy erstellen wir daraus Long- oder Shortaufträge, in der Condition setzen wir das „Occured“-Objekt, usw. In unserem Beispiel nutzen wir unser globales „ResultValue“-Objekt, natürlich kann aber auch deine eigene Klasse verwendet werden, falls zusützliche Attribute benötigt werden.
[pastacode lang=“java“ manual=“public%20class%20ResultValue_Example_Indicator_SMA_CrossOver_Advanced%0A%7B%0A%20%20%20%20public%20bool%20ErrorOccured%20%3D%20false%3B%0A%20%20%20%20public%20OrderAction%3F%20Entry%20%3D%20null%3B%0A%20%20%20%20public%20OrderAction%3F%20Exit%20%3D%20null%3B%0A%20%20%20%20public%20double%20Price%20%3D%200.0%3B%0A%20%20%20%20public%20double%20Slow%20%3D%200.0%3B%0A%20%20%20%20public%20double%20Fast%20%3D%200.0%3B%0A%7D“ message=““ highlight=““ provider=“manual“/]
Calculate Methode
Wir wollen unsere Hauptlogik in eine Hauptmethode kapseln. In unserem Fall machen wir das, indem wir die nachstehende öffentliche Methode im Indikator definieren.
[pastacode lang=“java“ manual=“public%20ResultValue_Example_Indicator_SMA_CrossOver_Advanced%20calculate(IDataSeries%20data%2C%20int%20fastsma%2C%20int%20slowsma%2C%20bool%20islongenabled%2C%20bool%20isshortenabled)%20%7B%0A%2F*%0A*%20Here%20we%20do%20all%20the%20smart%20work%20and%20in%20the%20end%20we%20return%20our%20result%20object.%0A*%20So%20the%20calling%20scripts%20knows%20what%20to%20do%20(e.g.%20a%20strategy%20will%20create%20an%20order%20in%20the%20market%2C%20the%20condition%20will%20create%20a%20signal%2C%20and%20so%20on).%0A*%2F%0A%7D“ message=““ highlight=““ provider=“manual“/]
So ist es möglich, dass andere Skripts einfach unsere „Calculate“-Methode des Indikators aufrufen können und dadurch die Entscheidung für den nächsten Schritt bekommen. In unserem Fall retourniert die „Calculate“-Methode ein Objekt, welches alle wichtigen Informationen für die Entscheidungsfindung beinhaltet. Wenn wir „OrderAction.Buy“ als „Entry“-Ergebnis bekommen, müssen wir einen Longauftrag in der Strategie starten oder den Conditionwert auf „1“ setzen.
Condition
Nach der Fertigstellung des Indikators können wir mit der Condition weiterarbeiten. Da wir bereits unser Tradingkonzept in die „Calculate“-Methode des Indikators hinzugefügt haben, müssen wir jetzt nur noch eine Referenz zu dem Indikator herstellen und wir sind schon fast fertig.
[pastacode lang=“java“ manual=“private%20Example_Indicator_SMA_CrossOver_Advanced%20_Example_Indicator_SMA_CrossOver_Advanced%20%3D%20null%3B%0A“ message=““ highlight=““ provider=“manual“/]
Wir müssen in der „OnStartUp“-Methode die Variable initialisieren:
[pastacode lang=“java“ manual=“protected%20override%20void%20OnStartUp()%0A%7B%0A%20%20%20%20%20base.OnStartUp()%3B%0A%0A%20%20%20%20%20%2F%2FInit%20our%20indicator%20to%20get%20code%20access%20to%20the%20calculate%20method%0A%20%20%20%20%20this._Example_Indicator_SMA_CrossOver_Advanced%20%3D%20new%20Example_Indicator_SMA_CrossOver_Advanced()%3B%0A%7D“ message=““ highlight=““ provider=“manual“/]
Nun sind wir bereit die „Calculate“-Methode des Indikators in unserer „OnBarUpdate“-Methode der Condition zu verwenden.
[pastacode lang=“java“ manual=“%2F%2FLets%20call%20the%20calculate%20method%20and%20save%20the%20result%20with%20the%20trade%20action%0AResultValue_Example_Indicator_SMA_CrossOver_Advanced%20returnvalue%20%3D%20this._Example_Indicator_SMA_CrossOver_Advanced.calculate(this.Input%2C%20this.FastSma%2C%20this.SlowSma%2C%20this.IsLongEnabled%2C%20this.IsShortEnabled)%3B“ message=““ highlight=““ provider=“manual“/]
In dem Code-Ausschnitt oberhalb sehen wir, dass der Returnvalue der „Calculate“-Methode unser „ResultValue“ vom Anfang des Tutorial ist. Hier müssen wir nur noch das Rückgabeobjekt auswerten.
[pastacode lang=“java“ manual=“%2F%2FEntry%0Aif%20(returnvalue.Entry.HasValue)%0A%7B%0A%20%20%20switch%20(returnvalue.Entry)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20case%20OrderAction.Buy%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FLong%20Signal%0A%20%20%20%20%20%20%20%20%20%20%20%20Occurred.Set(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Entry.Set(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0A%20%20%20%20%20%20%20%20case%20OrderAction.SellShort%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FShort%20Signal%0A%20%20%20%20%20%20%20%20%20%20%20%20Occurred.Set(-1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Entry.Set(-1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0A%20%20%20%20%7D%0A%7D%0Aelse%0A%7B%0A%20%20%20%2F%2FNo%20Signal%0A%20%20%20Occurred.Set(0)%3B%0A%20%20%20Entry.Set(0)%3B%0A%7D“ message=““ highlight=““ provider=“manual“/]
Strategie
Wir folgen nun dem gleichen Muster wie in unserer Condition. Wir erstellen eine Variable für die Indikator-Instanz, initialisieren diese Variable während der „OnStartUp“-Methode und benutzen diese Instanz in unserer „OnBarUpdate“-Methode.
Bitte achte darauf, dass beim Backtesten mit dem Parameter „Orders Handling Mode = Advanced“ mindestens zwei Bars benötigt werden!
[pastacode lang=“java“ manual=“%2F%2FBecause%20of%20backtesting%20reasons%20if%20we%20use%20the%20advanced%20mode%20we%20need%20at%20least%20two%20bars!%0A%2F%2FIn%20this%20case%20we%20are%20using%20SMA50%2C%20so%20we%20need%20at%20least%2050%20bars.%0Athis.BarsRequired%20%3D%2050%3B“ message=““ highlight=““ provider=“manual“/]
Wenn man die Strategie im Chart startet, wird der TimeFrame automatisch gesetzt. Wenn man die Strategie im „Strategie Escort“ startet, kann diese mit einer Defaul-TimeFrame gestartet werden. Eine solche Default-Timeframe kann in der „Initialize“-Methode gesetzt werden.
[pastacode lang=“java“ manual=“if%20(this.TimeFrame%20%3D%3D%20null%20%7C%7C%20this.TimeFrame.PeriodicityValue%20%3D%3D%200)%0A%7B%0A%20%20%20%20this.TimeFrame%20%3D%20new%20TimeFrame(DatafeedHistoryPeriodicity.Day%2C%201)%3B%0A%7D“ message=““ highlight=““ provider=“manual“/]
Wir setzen IsAutomated = true, um die Strategie vollautomatisch arbeiten zu lassen. In diesem Fall kann die Strategie im „Strategie Escort“ verwendet werden und erzeugt automatisch Ein- und Ausstiegsorders.
Am Ende der Strategiedatei sind vier Methoden: DoEnterLong(), DoEnterShort(), DoExitLong() und DoExitShort(). In diesen Methoden sind alle Regeln für die Auftragserstellung implementiert.
Sonstiges
Datei- und Klassennamen
Um alle Scripts im AgenaTrader ohne Fehler erstellen oder importieren zu können, haben wir jeweils die Postfixes „_indicator“, „_strategy“, „_condition“ bzw. „_alert“ zu den Dateinamen hinzugefügt. Das ist wichtig, da im AgenaTrader keine Dateinamen doppelt vorkommen dürfen! Es ist nicht möglich einen Indikator und eine Condition mit dem gleichen Namen, also beispielsweise „SMA_CrossOver“, zu speichern. Diese müssen eindeutige Namen besitzen, zB. „SMA_CrossOver_indicator“ und „SMA_CrossOver_condition“!
Farbe und „Drawing Style“
Wenn die Farbe bzw. „Drawing Style“ durch den User abweichend zum ursprünglichen Scriptvorschlagswert (bei Indikator bzw. Condition) geändert wurde, müssen diese Anpassungen in der „OnBarUpdate“-Methode ebenfalls geändert werden.
[pastacode lang=“java“ manual=“%2F%2FSet%20the%20drawing%20style%2C%20if%20the%20user%20has%20changed%20it.%0APlotColors%5B0%5D%5B0%5D%20%3D%20this.Plot0Color%3B%0APlots%5B0%5D.PenStyle%20%3D%20this.Dash0Style%3B%0APlots%5B0%5D.Pen.Width%20%3D%20this.Plot0Width%3B“ message=““ highlight=““ provider=“manual“/]
DisplayName und ToString()
In jedem Skript überschreiben wir die ToString() Methode und das DisplayName Attribut, um einen lesbaren Text im AgenaTrader anzeigen zu können. Dadurch wird ein lesbarer Text anstatt des Klassennamens im AgenaTrader angezeigt. In Klammer ergänzen wir „C“ für Condition, „I“ für Indikator, „A“ für Alarm und „S“ für Strategie um sicherzustellen, dass wir zwischen den Scripts unterscheiden können (zB wenn wir im Chart Indikatoren oder Conditions bearbeiten).
[pastacode lang=“java“ manual=“%2F%2F%2F%20%3Csummary%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20defines%20display%20name%20of%20indicator%20(e.g.%20in%20AgenaTrader%20chart%20window)%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2Fsummary%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3Creturns%3E%3C%2Freturns%3E%0A%20%20%20%20%20%20%20%20public%20override%20string%20ToString()%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%22Example%20SMA%20CrossOver%20Advanced%20(I)%22%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3Csummary%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20defines%20display%20name%20of%20indicator%20(e.g.%20in%20AgenaTrader%20indicator%20selection%20window)%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2Fsummary%3E%0A%20%20%20%20%20%20%20%20public%20override%20string%20DisplayName%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20get%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%22Example%20SMA%20CrossOver%20Advanced%20(I)%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D“ message=““ highlight=““ provider=“manual“/]