Dokumentation
Anwendungen
Zuletzt aktualisiert am 22. 2. 2022 von Mark Fric
Programmatische Durchführung von Strategie-Backtests
Inhalt der Seite
In diesem Beispiel wird gezeigt, wie man Strategie-Backtests programmatisch ausführen kann, indem man unsere Backtesting-Engine aufruft. Das Beispiel ist in Form eines benutzerdefinierten Analyse-Snippets erstellt.
Der Backtesting-Code kann theoretisch in jedes andere Snippet eingefügt werden, Sie müssen sich nur darüber im Klaren sein, dass Backtests langsam sind. Es ist also definitiv nicht empfehlenswert, Backtests in Datenbankspalten und ähnlichen anderen Snippets durchzuführen, die schnell sein müssen.
Sie können das komplette Snippet als Anhang zu diesem Artikel herunterladen, der vollständige Quellcode wird ebenfalls am Ende des Artikels veröffentlicht.
Wir werden die wichtigsten Teile des Backtests Schritt für Schritt beschreiben. Der Backtest selbst ist in der Methode Custom Analysis implementiert processDatabank()wo er einen benutzerdefinierten Backtest der allerersten Strategie in der Datenbank durchführt.
BacktestEngine zur Durchführung von Backtests verwenden
Die Durchführung eines Backtests ist relativ einfach, Sie müssen nur folgende Daten initialisieren BacktestEngine und rufen dann dessen Methode runBacktest() und dann getResults(), um das Backtest-Ergebnis zu erhalten.
// Erstellen eines Handelssimulators (später für die Backtest-Engine verwendet) ITradingSimulator simulator = new MetaTrader4Simulator(); // Testgenauigkeit für den Simulator festlegen simulator.setTestPrecision(Precisions.getPrecision(Precisions.PRECISION_BASE_TF)); // BacktestEngine unter Verwendung des Simulators erstellen BacktestEngine backtestEngine = new BacktestEngine(simulator); backtestEngine.setSingleThreaded(true); // Hinzufügen von Backtest-Einstellungen zur Engine backtestEngine.addSetup(einstellungen); // ------------------------ // Backtest ausführen - damit wird der eigentliche Backtest unter Verwendung der oben konfigurierten Einstellungen ausgeführt // Je nach den Einstellungen kann dies eine Weile dauern. // Nach Abschluss wird ein neues ResultsGroup-Objekt mit dem Backtest-Ergebnis zurückgegeben. // Im Falle eines Fehlers wird eine Exception mit der Beschreibung des Fehlers geworfen ResultsGroup backtestResultRG = backtestEngine.runBacktest().getResults();
Zunächst erstellen wir einen Handelssimulator eines bestimmten Typs (MT4, MT5, Tradestation usw.) und stellen dessen Backtest-Präzision ein.
Dann erstellen wir BacktestEngine unter Verwendung dieses Simulators. Wir müssen der Engine Einstellungen hinzufügen, die andere Backtest-Parameter beschreiben, indem wir addSetup() - Die Einstellungen selbst werden später erklärt.
Der letzte Punkt ist der Anruf runBacktest().getResults() um den eigentlichen Backtest durchzuführen und die Ergebnisse zu erhalten.
Einstellungen für Backtest erstellen
BacktestEngine muss mit Einstellungen konfiguriert werden - einem SettingsMap-Objekt. Dabei handelt es sich um eine Karte mit Schlüssel-Werte-Paaren, in der Sie verschiedene Parameter des Backtests einstellen können.
SettingsMap settings = new SettingsMap(); // Chart-Setup für Backtest vorbereiten - Sie müssen den Datennamen, den Bereich usw. angeben ChartSetup chartSetup = new ChartSetup( "Historie", // dies ist eine Konstante "EURUSD_M1", // Symbolname, muss mit dem Namen im Datenmanager übereinstimmen TimeframeManager.TF_H1, // Zeitrahmen SQTimeOld.toLong(2008, 4, 20), // Datum von SQTimeOld.toLong(2009, 6, 29), // Datum bis 3.5, // Spanne Session.Forex_247 // Sitzung ); settings.set(SettingsKeys.BacktestChart, chartSetup); // andere Backtest-Einstellungen vorbereiten - dadurch werden andere optionale/erforderliche Teile in die Settings-Map eingefügt prepareBacktestSettings(settings, strategyToRetest);
Sie können sehen, dass wir zuerst die EinstellungenKarte Objekt. Wir definieren dann ChartSetup - Es handelt sich um eine Konfiguration von Daten, die für Backtests verwendet werden, und sie wird zu den Einstellungen hinzugefügt, indem man settings.set(SettingsKeys.BacktestChart, chartSetup).
Der letzte Aufruf ist die Methode prepareBacktestSettings(...) die den Rest der Einstellungen festlegt, um den Code einfacher und lesbarer zu halten.
Methode prepareBacktestSettings()
Es ist die Methode, die andere optionale und erforderliche Konfigurationswerte für die Backtest-Einstellungen festlegt - wie Strategie, Geldmanagement, Anfangskapital, Handelsoptionen und so weiter.
private void prepareBacktestSettings(SettingsMap settings,ResultsGroup strategyToRetest) throws Exception { // erstellt Strategieobjekt aus Strategie-XML, das in der Quell-Ergebnisgruppe gespeichert ist String strategyName = strategyToRetest.getName(); Element elStrategy = strategyToRetest.getStrategyXml(); if(elStrategy == null) { // Ergebnis hat keine Strategie, kann nicht getestet werden throw new Exception("Ergebnis hat keine Strategie, kann nicht getestet werden!"); } StrategyBase strategy = StrategyBase.createXmlStrategy(elStrategy.clone(), strategyName); settings.set(SettingsKeys.StrategyObject, strategy); settings.set(SettingsKeys.MinimumDistance, 0); // Anfangskapital und Geldmanagement einstellen settings.set(SettingsKeys.InitialCapital, 100000d); settings.set(SettingsKeys.MoneyManagement, MoneyManagementMethodsList.create("FixedSize", 0.1)); // Hinweis: Sie können eine andere MoneyManagement-Methode erstellen, indem Sie den (Schnipsel-)Namen // und Parameter in der exakten Reihenfolge angeben, zum Beispiel: // MoneyManagementMethodsList.create("RiskFixedPctOfAccount", 5, 100, 0.1, 0.5)) // Erforderliche Handelsoptionen erstellen und einstellen TradingOptions options = createTradingOptions(); settings.set(SettingsKeys.TradingOptions, options); }
Der Code ist kommentiert, und Sie sollten in der Lage sein zu verstehen, was er tut. Es gibt wieder eine separate Untermethode createTradingOptions() verwendet, um den Code übersichtlicher zu gestalten. Diese Methode wird hier nicht erklärt, sie ist im Code kommentiert und gibt eine Liste von Handelsoptionen zurück, die für den Backtest gelten sollen.
Arbeiten mit Backtest-Ergebnis
Wenn Ihr Backtest erfolgreich abgeschlossen wurde, erhalten Sie eine neue ErgebnisGruppe Objekt mit Backtest-Ergebnis. Sie können dann im Allgemeinen zwei Dinge damit tun:
- Lesen Sie die Metriken (Anzahl der Trades, Nettogewinn, Sharpe usw.), um festzustellen, ob Sie die Strategie herausfiltern möchten.
- Speichern des Ergebnisses in einer Datenbank oder in einer Datei
Beides ist ganz einfach:
// 1. die Metrikwerte abrufen und sie auf irgendeine Weise vergleichen/filtern, Beispiel: int trades = backtestResultRG.portfolio().stats(Directions.Both, PlTypes.Money, SampleTypes.FullSample).getInt(StatsKey.NUMBER_OF_TRADES); double profit = backtestResultRG.portfolio().stats(Directions.Both, PlTypes.Money, SampleTypes.FullSample).getDouble(StatsKey.NET_PROFIT); // nun etwas mit diesen Werten tun Log.info("Trades: {}, Gewinn: {}", Trades, Gewinn); // 2. den neuen Backtest in einer Datenbank oder Datei speichern SQProject project = ProjectEngine.get(projectName); if(projekt == null) { throw new Exception("Projekt '"+Projektname+"' kann nicht geladen werden!"); } Databank targetDB = project.getDatabanks().get("Results"); if(targetDB == null) { throw new Exception("Zieldatenbank 'Ergebnisse' wurde nicht gefunden!"); } // Hinzufügen der neuen Strategie+Backtest zu dieser Datenbank und Aktualisieren des Datenbankgitters targetDB.add(backtestResultRG, true);
Vollständiger Quellcode des CAStrategyTestByProgramming-Snippets:
Paket SQ.CustomAnalysis; import SQ.TradingOptions.*; import com.strategyquant.datalib.TimeframeManager; import com.strategyquant.datalib.consts.Precisions; import com.strategyquant.datalib.session.Session; import com.strategyquant.lib.SettingsMap; import com.strategyquant.lib.time.SQTimeOld; import com.strategyquant.tradinglib.*; import com.strategyquant.tradinglib.engine.BacktestEngine; import com.strategyquant.tradinglib.moneymanagement.MoneyManagementMethodsList; import com.strategyquant.tradinglib.options.TradingOptions; import com.strategyquant.tradinglib.options.TradingOptions; import com.strategyquant.tradinglib.simulator.Engines; import com.strategyquant.tradinglib.simulator.ITradingSimulator; import com.strategyquant.tradinglib.simulator.impl.*; import com.strategyquant.tradinglib.project.ProjectEngine; import com.strategyquant.tradinglib.project.SQProject; import com.strategyquant.tradinglib.project.SQProject; import org.jdom2.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; public class CAStrategyTestByProgramming extends CustomAnalysisMethod { public static final Logger Log = LoggerFactory.getLogger("CAStrategyTestByProgramming"); //------------------------------------------------------------------------ //------------------------------------------------------------------------ //------------------------------------------------------------------------ public CAStrategyTestByProgrammierung() { super("CAStrategyTestByProgramming", TYPE_PROCESS_DATABANK); } //------------------------------------------------------------------------ @Override public boolean filterStrategy(String projectName, String task, String databankName, ResultsGroup rg) throws Exception { return false; } //------------------------------------------------------------------------ @Override public ArrayList processDatabank(String projectName, String task, String databankName, ArrayList databankRG) throws Exception { if(databankRG.size() == 0) { return databankRG; } // holt die erste Strategie in der Datenbank, um einen erneuten Test damit durchzuführen ErgebnisGruppe strategyToRetest = databankRG.get(0); // wir speichern alle Einstellungen für den neuen Backtest in dieser SettingsMap SettingsMap settings = new SettingsMap(); // Bereiten Sie das Chart-Setup für den Backtest vor - Sie müssen den Datennamen, den Bereich, etc. angeben ChartSetup chartSetup = new ChartSetup( "Historie", // dies ist eine Konstante "EURUSD_M1", // Symbolname, muss mit dem Namen im Datenmanager übereinstimmen TimeframeManager.TF_H1, // Zeitrahmen SQTimeOld.toLong(2008, 4, 20), // Datum von SQTimeOld.toLong(2009, 6, 29), // Datum bis 3.5, // Spanne Session.Forex_247 // Sitzung ); settings.set(SettingsKeys.BacktestChart, chartSetup); // andere Backtest-Einstellungen vorbereiten - dadurch werden andere optionale/erforderliche Teile in die Settings-Map eingefügt prepareBacktestSettings(settings, strategyToRetest); // Handelssimulator erstellen (wird später für die Backtest-Engine verwendet) ITradingSimulator simulator = new MetaTrader4Simulator(); // verfügbare Simulatoren: //MetaTrader4Simulator() //MetaTrader5SimulatorHedging(OrderExecutionTypes.EXCHANGE) //MetaTrader5SimulatorNetting(OrderExecutionTypes.EXCHANGE) //TradestationSimulator() //MultiChartsSimulator() //JForexSimulator() // Testgenauigkeit für den Simulator festlegen simulator.setTestPrecision(Precisions.getPrecision(Precisions.PRECISION_BASE_TF)); // Verfügbare Genauigkeit (hängt auch von den Daten ab - Sie können keine Tick-Präzision verwenden, wenn Sie keine Tick-Daten haben): //PRECISION_SELECTED_TF = "Nur ausgewählter Zeitrahmen (schnellster)"; //PRECISION_BASE_TF = "1 Minute Daten-Tick-Simulation (langsam)"; //PRECISION_TICK_CUSTOM_SPREADS = "Real Tick - benutzerdefinierter Spread (am langsamsten)"; //PRECISION_TICK_REAL_SPREADS = "Real Tick - realer Spread (am langsamsten)"; //PRECISION_OPEN_PRICES = "Trade On Bar Open"; // BacktestEngine mit Simulator erstellen BacktestEngine backtestEngine = new BacktestEngine(simulator); backtestEngine.setSingleThreaded(true); // Hinzufügen von Backtest-Einstellungen zur Engine backtestEngine.addSetup(einstellungen); // ------------------------ // Backtest ausführen - damit wird der eigentliche Backtest unter Verwendung der oben konfigurierten Einstellungen ausgeführt // Abhängig von den Einstellungen kann dies eine Weile dauern. // Nach Beendigung wird ein neues ResultsGroup-Objekt mit dem Backtest-Ergebnis zurückgegeben. // Im Falle eines Fehlers wird eine Exception mit der Beschreibung des Fehlers geworfen ResultsGroup backtestResultRG = backtestEngine.runBacktest().getResults(); // holt Details zu den Backtest-Ergebnissen - hier können Sie auf alle Ergebnisse in ResultsGroup zugreifen // und etwas mit ihnen machen. // Sie können im Allgemeinen zwei Dinge tun: // 1. die Metrikwerte abrufen und sie auf irgendeine Weise vergleichen / filtern, Beispiel: int trades = backtestResultRG.portfolio().stats(Directions.Both, PlTypes.Money, SampleTypes.FullSample).getInt(StatsKey.NUMBER_OF_TRADES); double profit = backtestResultRG.portfolio().stats(Directions.Both, PlTypes.Money, SampleTypes.FullSample).getDouble(StatsKey.NET_PROFIT); // Machen Sie nun etwas mit diesen Werten // Zum Beispiel können Sie das Ergebnis dieses benutzerdefinierten Backtests verwenden, um diese bestimmte Strategie herauszufiltern // aus der Datenbank herausfiltern, indem sie aus dem Array databankRG entfernt wird Log.info("Trades: {}, Gewinn: {}", Trades, Gewinn); // 2. der neue Backtest kann in einer Datenbank oder Datei gespeichert werden SQProject project = ProjectEngine.get(projectName); if(projekt == null) { throw new Exception("Projekt '"+Projektname+"' kann nicht geladen werden!"); } Databank targetDB = project.getDatabanks().get("Results"); if(targetDB == null) { throw new Exception("Zieldatenbank 'Ergebnisse' wurde nicht gefunden!"); } // Hinzufügen der neuen Strategie+Backtest zu dieser Datenbank und Aktualisieren des Datenbankgitters targetDB.add(backtestResultRG, true); // Methode muss eine Liste der ursprünglichen Strategien in der Datenbank zurückgeben, die diesen Filter bestanden haben return databankRG; } //------------------------------------------------------------------------ private void prepareBacktestSettings(SettingsMap settings,ResultsGroup strategyToRetest) throws Exception { // erstellt Strategieobjekt aus Strategie-XML, das in der Quelle ResultsGroup gespeichert ist String strategyName = strategyToRetest.getName(); Element elStrategy = strategyToRetest.getStrategyXml(); if(elStrategy == null) { // Ergebnis hat keine Strategie, kann nicht getestet werden throw new Exception("Ergebnis hat keine Strategie, kann nicht getestet werden!"); } StrategyBase strategy = StrategyBase.createXmlStrategy(elStrategy.clone(), strategyName); settings.set(SettingsKeys.StrategyObject, strategy); settings.set(SettingsKeys.MinimumDistance, 0); // Anfangskapital und Geldmanagement einstellen settings.set(SettingsKeys.InitialCapital, 100000d); settings.set(SettingsKeys.MoneyManagement, MoneyManagementMethodsList.create("FixedSize", 0.1)); // Hinweis - Sie können eine andere MoneyManagement-Methode erstellen, indem Sie ihren (Schnipsel-)Namen // und Parameter in der exakten Reihenfolge angeben, zum Beispiel: // MoneyManagementMethodsList.create("RiskFixedPctOfAccount", 5, 100, 0.1, 0.5)) // Erforderliche Handelsoptionen erstellen und einstellen TradingOptions options = createTradingOptions(); settings.set(SettingsKeys.TradingOptions, options); } //------------------------------------------------------------------------ private HandelsOptionen createTradingOptions() { TradingOptions options = new TradingOptions(); // alle Handelsoptionen werden als Snippets definiert // in SQ.TradingOptions.* (sichtbar im CodeEditor) // Nachstehend ein Beispiel für die Anwendung einiger dieser Optionen ExitAtEndOfDay option = new ExitAtEndOfDay(); option.ExitAtEndOfDay = true; option.EODExitTime = 0; options.add(option); ExitOnFriday option2 = new ExitOnFriday(); option2.ExitOnFriday = true; option2.FridayExitTime = 0; options.add(option2); LimitTimeRange option3 = new LimitTimeRange(); option3.LimitTimeRange = true; option3.SignalTimeRangeFrom = 700; option3.SignalTimeRangeTo = 1900; option3.ExitAtEndOfRange = true; options.add(option3); MinMaxSLPT optionMmSLPT = new MinMaxSLPT(); optionMmSLPT.MinimumSL = 50; optionMmSLPT.MaximumSL = 100; optionMmSLPT.MinimumPT = 50; optionMmSLPT.MaximumPT = 100; options.add(optionMmSLPT); Optionen zurückgeben; } }
War dieser Artikel hilfreich? Der Artikel war nützlich Der Artikel war nicht nützlich
Ausgezeichnet !!! Sehr gute Idee und sehr nützlich !!!! Ich wusste nicht, dass wir SQX bitten können, einen Backtest von Java aus durchzuführen.
Wir können sogar den Motor, die Strategie # und den Zeitraum auswählen. Ich werde es verwenden !!!!
SQX ist wirklich erstaunlich
Mit Beispielen wie diesem lerne ich eine Menge, danke SQX-Team !!!!!
Ich erhalte eine kleine Fehlermeldung "Import fehlgeschlagen.Erwartete Datei mit der Erweiterung .sxp” ?
Ich habe V 135.368."
Seltsam, die Datei hat die Erweiterung sxpIch habe diesen Fehler, wenn ich es importiere
Was sollte ich tun, um diesen Fehler zu vermeiden?