Documentazione
Applicazioni
Ultimo aggiornamento il 22. 2. 2022 da Mark Fric
Esecuzione programmatica dei backtest delle strategie
Contenuto della pagina
Questo esempio mostra come eseguire i backtest delle strategie in modo programmatico, chiamando il nostro motore di backtesting. L'esempio è realizzato sotto forma di snippet di analisi personalizzata.
Il codice di backtesting può essere teoricamente incluso in qualsiasi altro snippet, ma è sufficiente rendersi conto che i backtest sono lenti, quindi è assolutamente sconsigliato eseguire backtest in colonne di banche dati e altri snippet simili che devono essere veloci.
È possibile scaricare lo snippet completo come allegato a questo articolo; il codice sorgente completo sarà pubblicato anche alla fine dell'articolo.
Descriviamo passo per passo le parti più importanti del backtest. Il backtest stesso è implementato nel metodo Analisi personalizzata elaboraBancaDati()dove viene eseguito un backtest personalizzato della prima strategia presente nella banca dati.
Utilizzo di BacktestEngine per l'esecuzione di backtest
L'esecuzione del backtest è relativamente semplice: è sufficiente inizializzare BacktestEngine e poi chiamare il suo metodo runBacktest() e poi getResults() per ottenere il risultato del backtest.
// creare un simulatore di trading (utilizzato in seguito per il motore di backtest) ITradingSimulator simulator = new MetaTrader4Simulator(); // imposta la precisione di prova per il simulatore simulator.setTestPrecision(Precisions.getPrecision(Precisions.PRECISION_BASE_TF)); // creare il motore di backtest utilizzando il simulatore BacktestEngine backtestEngine = new BacktestEngine(simulatore); backtestEngine.setSingleThreaded(true); // aggiungere le impostazioni di backtest al motore backtestEngine.addSetup(settings); // ------------------------ // Eseguire il backtest - questo eseguirà il backtest vero e proprio utilizzando le impostazioni configurate in precedenza. // A seconda delle impostazioni, potrebbe volerci un po' di tempo. // Al termine, restituirà un nuovo oggetto ResultsGroup con i risultati del backtest. // In caso di errore viene lanciata un'Eccezione con la descrizione dell'errore ResultsGroup backtestResultRG = backtestEngine.runBacktest().getResults();
Per prima cosa creiamo un simulatore di trading di un determinato tipo (MT4, MT5, Tradestation, ecc.) e impostiamo la precisione del backtest.
Poi creeremo BacktestEngine utilizzando questo simulatore. È necessario aggiungere al motore le impostazioni che descrivono altri parametri del backtest utilizzando addSetup() - le impostazioni stesse saranno spiegate in seguito.
L'ultima cosa è chiamare runBacktest().getResults() per eseguire il backtest vero e proprio e ottenerne i risultati.
Creazione delle impostazioni per il backtest
BacktestEngine deve essere configurato con le impostazioni - un oggetto SettingsMap. Si tratta di una mappa di coppie chiave -> valore, in cui è possibile impostare vari parametri del backtest.
SettingsMap settings = new SettingsMap(); // preparare il setup del grafico per il backtest - è necessario specificare il nome dei dati, l'intervallo, ecc. ChartSetup chartSetup = new ChartSetup( "History", // questa è una costante "EURUSD_M1", // nome del simbolo, deve corrispondere al nome nel Data Manager TimeframeManager.TF_H1, // timeframe SQTimeOld.toLong(2008, 4, 20), // data a partire da SQTimeOld.toLong(2009, 6, 29), // data al 3.5, // spread Session.Forex_247 // sessione ); settings.set(SettingsKeys.BacktestChart, chartSetup); // preparare le altre impostazioni del backtest - questo metterà altre parti opzionali/richieste nella mappa delle impostazioni prepareBacktestSettings(settings, strategyToRetest);
Si può notare che prima si crea il file ImpostazioniMappa oggetto. Definiamo quindi Impostazione dei grafici - è una configurazione dei dati utilizzati per il backtest e viene aggiunta alle impostazioni chiamando settings.set(SettingsKeys.BacktestChart, chartSetup).
L'ultima chiamata è il metodo prepareBacktestSettings(...) che imposterà il resto delle impostazioni per mantenere il codice più semplice e leggibile.
Metodo prepareBacktestSettings()
È il metodo che imposta altri valori di configurazione facoltativi e obbligatori per le impostazioni del backtest, come la strategia, la gestione del denaro, il capitale iniziale, le opzioni di trading e così via.
private void prepareBacktestSettings(SettingsMap settings,ResultsGroup strategyToRetest) throws Exception { // crea l'oggetto strategia dall'XML della strategia memorizzato nel ResultsGroup di origine String strategyName = strategyToRetest.getName(); Element elStrategy = strategyToRetest.getStrategyXml(); if(elStrategy == null) { // il risultato non ha alcuna strategia, non può essere testato throw new Exception("Il risultato non ha alcuna strategia, non può essere testato!"); } StrategyBase strategy = StrategyBase.createXmlStrategy(elStrategy.clone(), strategyName); settings.set(SettingsKeys.StrategyObject, strategy); settings.set(SettingsKeys.MinimumDistance, 0); // impostare il capitale iniziale e la gestione del denaro settings.set(SettingsKeys.InitialCapital, 100000d); settings.set(SettingsKeys.MoneyManagement, MoneyManagementMethodsList.create("FixedSize", 0.1)); // Nota: è possibile creare un metodo di gestione del denaro diverso specificandone il nome (snippet) e i parametri nell'ordine esatto. // e i parametri nel loro ordine esatto, ad esempio: // MoneyManagementMethodsList.create("RiskFixedPctOfAccount", 5, 100, 0.1, 0.5)) // creare e impostare le opzioni di trading richieste TradingOptions options = createTradingOptions(); settings.set(SettingsKeys.TradingOptions, options); }
Il codice è commentato e si dovrebbe essere in grado di capire cosa fa. C'è di nuovo un sotto-metodo separato creareOpzioni di trading() utilizzato per mantenere il codice più organizzato. Questo metodo non sarà spiegato qui, è commentato nel codice e restituisce un elenco di opzioni di trading da applicare al backtest.
Lavorare con i risultati del backtest
Quando il backtest è terminato con successo, si otterrà un nuovo file Gruppo di risultati con il risultato del backtest. In genere, si possono fare due cose con esso:
- Leggete le sue metriche (numero di operazioni, profitto netto, Sharpe, ecc.) per determinare se volete filtrare la strategia.
- Salvare il risultato in una banca dati o in un file.
Entrambe le cose sono abbastanza semplici:
// 1. Ottenere i valori delle metriche e confrontarli / filtrarli in qualche modo, ad esempio: 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); // ora facciamo qualcosa con questi valori Log.info("Operazioni: {}, profitto: {}", operazioni, profitto); // 2. Si può salvare il nuovo backtest in una banca dati o in un file SQProject project = ProjectEngine.get(projectName); if(project == null) { throw new Exception("Il progetto '"+projectName+"' non può essere caricato!"); } Databank targetDB = project.getDatabanks().get("Results"); if(targetDB == null) { throw new Exception("La banca dati di destinazione 'Risultati' non è stata trovata!"); } // Aggiungiamo la nuova strategia+backtest a questa banca dati e aggiorniamo la griglia della banca dati. targetDB.add(backtestResultRG, true);
Codice sorgente completo dello snippet CAStrategyTestByProgramming:
pacchetto SQ.CustomAnalysis; importare SQ.TradingOptions.*; importare com.strategyquant.datalib.TimeframeManager; importare com.strategyquant.datalib.consts.Precisions; importare com.strategyquant.datalib.session.Session; importare com.strategyquant.lib.SettingsMap; importare com.strategyquant.lib.time.SQTimeOld; importare com.strategyquant.tradinglib.*; importare com.strategyquant.tradinglib.engine.BacktestEngine; importare com.strategyquant.tradinglib.moneymanagement.MoneyManagementMethodsList; importare com.strategyquant.tradinglib.options.TradingOptions; importare com.strategyquant.tradinglib.simulator.Engines; importare com.strategyquant.tradinglib.simulator.ITradingSimulator; importare com.strategyquant.tradinglib.simulator.impl.*; importare com.strategyquant.tradinglib.project.ProjectEngine; importare com.strategyquant.tradinglib.project.SQProject; importare org.jdom2.Element; importare org.slf4j.Logger; import org.slf4j.LoggerFactory; importare java.util.ArrayList; public class CAStrategyTestByProgramming extends CustomAnalysisMethod { public static final Logger Log = LoggerFactory.getLogger("CAStrategyTestByProgramming"); //------------------------------------------------------------------------ //------------------------------------------------------------------------ //------------------------------------------------------------------------ public CAStrategyTestByProgramming() { 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; } // ottenere la prima strategia nella banca dati per eseguire il retest su di essa ResultsGroup strategyToRetest = databankRG.get(0); // memorizzeremo tutte le impostazioni per il nuovo backtest in questa SettingsMap SettingsMap settings = new SettingsMap(); // prepariamo l'impostazione del grafico per il backtest - è necessario specificare il nome dei dati, l'intervallo, ecc. ChartSetup chartSetup = new ChartSetup( "History", // questa è una costante "EURUSD_M1", // nome del simbolo, deve corrispondere al nome nel Data Manager TimeframeManager.TF_H1, // timeframe SQTimeOld.toLong(2008, 4, 20), // data a partire da SQTimeOld.toLong(2009, 6, 29), // data al 3.5, // spread Session.Forex_247 // sessione ); settings.set(SettingsKeys.BacktestChart, chartSetup); // preparare le altre impostazioni del backtest - questo metterà altre parti opzionali/richieste nella mappa delle impostazioni prepareBacktestSettings(settings, strategyToRetest); // creare il simulatore di trading (utilizzato successivamente per il motore di backtest) ITradingSimulator simulator = new MetaTrader4Simulator(); // simulatori disponibili: //MetaTrader4Simulator() //MetaTrader5SimulatorHedging(OrderExecutionTypes.EXCHANGE) //MetaTrader5SimulatorNetting(OrderExecutionTypes.EXCHANGE) //TradestationSimulator() //MultiChartsSimulator() //JForexSimulator() // imposta la precisione di prova per il simulatore simulator.setTestPrecision(Precisions.getPrecision(Precisions.PRECISION_BASE_TF)); // Precisioni disponibili (a seconda anche dei dati - non è possibile utilizzare la precisione tick se non si dispone di dati tick): //PRECISION_SELECTED_TF = "Solo il timeframe selezionato (il più veloce)"; //PRECISION_BASE_TF = "Simulazione di tick di dati a 1 minuto (lento)"; //PRECISION_TICK_CUSTOM_SPREADS = "Tick reali - spread personalizzato (il più lento)"; //PRECISION_TICK_REAL_SPREADS = "Tick reali - spread reale (più lento)"; //PRECISION_OPEN_PRICES = "Negoziazione all'apertura della barra"; // creare un motore di backtest utilizzando il simulatore BacktestEngine backtestEngine = new BacktestEngine(simulatore); backtestEngine.setSingleThreaded(true); // aggiungere le impostazioni di backtest al motore backtestEngine.addSetup(settings); // ------------------------ // Eseguire il backtest - questo eseguirà il backtest vero e proprio utilizzando le impostazioni configurate in precedenza. // A seconda delle impostazioni, potrebbe volerci un po' di tempo. // Al termine, restituirà un nuovo oggetto ResultsGroup con i risultati del backtest. // In caso di errore viene lanciata un'Eccezione con la descrizione dell'errore ResultsGroup backtestResultRG = backtestEngine.runBacktest().getResults(); // ottenere i dettagli dei risultati del backtest - qui è possibile accedere a tutti i risultati in ResultsGroup // e fare qualcosa con essi. // In genere si possono fare due cose: // 1. Ottenere i valori delle metriche e confrontarli / filtrarli in qualche modo, ad esempio: 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); // Ora fate qualcosa con questi valori // Per esempio, è possibile utilizzare il risultato di questo backtest personalizzato per filtrare questa particolare strategia // dalla banca dati, rimuovendola dall'array databankRG Log.info("Operazioni: {}, profitto: {}", operazioni, profitto); // 2. Si può salvare il nuovo backtest in un database o in un file SQProject project = ProjectEngine.get(projectName); if(project == null) { throw new Exception("Project '"+projectName+"' cannot be loaded!"); } Databank targetDB = project.getDatabanks().get("Results"); if(targetDB == null) { throw new Exception("La banca dati di destinazione 'Risultati' non è stata trovata!"); } // Aggiungiamo la nuova strategia+backtest a questa banca dati e aggiorniamo la griglia della banca dati. targetDB.add(backtestResultRG, true); // il metodo deve restituire un elenco di strategie originali nella banca dati che hanno superato questo filtro restituire databankRG; } //------------------------------------------------------------------------ private void prepareBacktestSettings(SettingsMap settings,ResultsGroup strategyToRetest) throws Exception { // crea l'oggetto strategia dall'XML della strategia memorizzato nel ResultsGroup di origine String strategyName = strategyToRetest.getName(); Element elStrategy = strategyToRetest.getStrategyXml(); if(elStrategy == null) { // il risultato non ha alcuna strategia, non può essere testato throw new Exception("Il risultato non ha alcuna strategia, non può essere testato!"); } StrategyBase strategy = StrategyBase.createXmlStrategy(elStrategy.clone(), strategyName); settings.set(SettingsKeys.StrategyObject, strategy); settings.set(SettingsKeys.MinimumDistance, 0); // impostare il capitale iniziale e la gestione del denaro settings.set(SettingsKeys.InitialCapital, 100000d); settings.set(SettingsKeys.MoneyManagement, MoneyManagementMethodsList.create("FixedSize", 0.1)); // Nota: è possibile creare un metodo di gestione del denaro diverso specificandone il nome (snippet) e i parametri nell'ordine esatto. // e i parametri nel loro ordine esatto, ad esempio: // MoneyManagementMethodsList.create("RiskFixedPctOfAccount", 5, 100, 0.1, 0.5)) // creare e impostare le opzioni di trading richieste TradingOptions options = createTradingOptions(); settings.set(SettingsKeys.TradingOptions, options); } //------------------------------------------------------------------------ private TradingOptions createTradingOptions() { TradingOptions options = new TradingOptions(); // tutte le opzioni di trading sono definite come snippet // in SQ.TradingOptions.* (visibile nel CodeEditor) // di seguito è riportato un esempio di applicazione di alcune di esse 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); restituire le opzioni; } }
Questo articolo è stato utile? L'articolo è stato utile L'articolo non è stato utile
Eccellente!!! Ottima idea e molto utile !!!! Non sapevo che si potesse chiedere a SQX di eseguire un backtest da Java.
Possiamo anche selezionare il motore, la strategia # e il periodo. Lo utilizzerò !!!!
SQX è davvero incredibile
Con esempi come questo, sto imparando molto, grazie al team SQX !!!!!
Ricevo un piccolo errore "Importazione fallita.File atteso con estensione .sxp” ?
Ho V 135.368".
Strano, il file ha l'estensione sxpHo questo errore quando lo importo
Cosa devo fare per evitare questo errore?