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?
Posso ottenere i valori degli indicatori da ITSimulatore di trading o BackTestEngine o HistoryDataLoader?
Grazie!