AgenaScriptAgenaTraderDeutsch

Tutorial: Wie benutzt man einen Indikator in einer Condition bzw. Strategie im AgenaTrader (fortgeschritten)

Dieses Tutorial zeigt ein fortgeschrittenes Beispiel für Indikatoren, Conditions und Strategien und zeigt dir, wie die einzelnen Scripts miteinander kommunizeren können.

Download Quelltext Dateien

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.

public class ResultValue_Example_Indicator_SMA_CrossOver_Advanced
{
    public bool ErrorOccured = false;
    public OrderAction? Entry = null;
    public OrderAction? Exit = null;
    public double Price = 0.0;
    public double Slow = 0.0;
    public double Fast = 0.0;
}

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.

public ResultValue_Example_Indicator_SMA_CrossOver_Advanced calculate(IDataSeries data, int fastsma, int slowsma, bool islongenabled, bool isshortenabled) {
/*
* Here we do all the smart work and in the end we return our result object.
* So the calling scripts knows what to do (e.g. a strategy will create an order in the market, the condition will create a signal, and so on).
*/
}

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.

private Example_Indicator_SMA_CrossOver_Advanced _Example_Indicator_SMA_CrossOver_Advanced = null;

Wir müssen in der „OnStartUp“-Methode die Variable initialisieren:

protected override void OnStartUp()
{
     base.OnStartUp();

     //Init our indicator to get code access to the calculate method
     this._Example_Indicator_SMA_CrossOver_Advanced = new Example_Indicator_SMA_CrossOver_Advanced();
}

Nun sind wir bereit die „Calculate“-Methode des Indikators in unserer „OnBarUpdate“-Methode der Condition zu verwenden.

//Lets call the calculate method and save the result with the trade action
ResultValue_Example_Indicator_SMA_CrossOver_Advanced returnvalue = this._Example_Indicator_SMA_CrossOver_Advanced.calculate(this.Input, this.FastSma, this.SlowSma, this.IsLongEnabled, this.IsShortEnabled);

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.

//Entry
if (returnvalue.Entry.HasValue)
{
   switch (returnvalue.Entry)
    {
        case OrderAction.Buy:
            //Long Signal
            Occurred.Set(1);
            Entry.Set(1);
            break;
        case OrderAction.SellShort:
            //Short Signal
            Occurred.Set(-1);
            Entry.Set(-1);
            break;
    }
}
else
{
   //No Signal
   Occurred.Set(0);
   Entry.Set(0);
}

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!

//Because of backtesting reasons if we use the advanced mode we need at least two bars!
//In this case we are using SMA50, so we need at least 50 bars.
this.BarsRequired = 50;

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.

if (this.TimeFrame == null || this.TimeFrame.PeriodicityValue == 0)
{
    this.TimeFrame = new TimeFrame(DatafeedHistoryPeriodicity.Day, 1);
}

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.

//Set the drawing style, if the user has changed it.
PlotColors[0][0] = this.Plot0Color;
Plots[0].PenStyle = this.Dash0Style;
Plots[0].Pen.Width = this.Plot0Width;

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

/// <summary>
        /// defines display name of indicator (e.g. in AgenaTrader chart window)
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return "Example SMA CrossOver Advanced (I)";
        }

        /// <summary>
        /// defines display name of indicator (e.g. in AgenaTrader indicator selection window)
        /// </summary>
        public override string DisplayName
        {
            get
            {
                return "Example SMA CrossOver Advanced (I)";
            }
        }

 

Share