### Full CAChangeTaskConfig Example Source: https://strategyquant.com/doc/programming-for-sq/changing-task-config-programmatically A complete example demonstrating how to retrieve, modify, and apply task configurations programmatically within a custom analysis method. It includes setting date ranges for the first setup. ```java package SQ.CustomAnalysis; import com.strategyquant.lib.SQTime; import com.strategyquant.lib.XMLUtil; import com.strategyquant.lib.constants.SQConst; import com.strategyquant.tradinglib.CustomAnalysisMethod; import com.strategyquant.tradinglib.ResultsGroup; import com.strategyquant.tradinglib.project.ProjectEngine; import com.strategyquant.tradinglib.project.SQProject; import com.strategyquant.tradinglib.project.websocket.DataToSend; import com.strategyquant.tradinglib.project.websocket.SQWebSocketManager; import com.strategyquant.tradinglib.project.websocket.WebSocketConst; import com.strategyquant.tradinglib.taskImpl.ISQTask; import org.jdom2.Element; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.json.JSONObject; import java.io.File; import java.util.ArrayList; import java.util.List; public class CAChangeTaskConfig extends CustomAnalysisMethod { //------------------------------------------------------------------------ //------------------------------------------------------------------------ //------------------------------------------------------------------------ public CAChangeTaskConfig() { super("CAChangeTaskConfig", TYPE_PROCESS_DATABANK); } //------------------------------------------------------------------------ @Override public ArrayList processDatabank(String project, String task, String databankName, ArrayList databankRG) throws Exception { // get current project SQProject sqProject = ProjectEngine.get(project); // get task by name ISQTask buildTask = sqProject.getTaskByName("Build strategies"); if(buildTask == null) { throw new Exception("No such task exists!"); } // alternatively you can use sqProject.getTasks() to get a list of all tasks // and go through them to get the one you want // this is how you get task settings XML in the new way (SQ 136 up) // It returns JDOM XML Element with full task configuration Element elConfig = buildTask.getConfig(); // create a new config by cloning it - it is important to make a clone, // otherwise your new config will be not applied Element elNewConfig = elConfig.clone(); // now change anything in the new config Element data = XMLUtil.getChildElem(elNewConfig, "Data"); Element setups = data.getChild("Setups"); List setupList = setups.getChildren("Setup"); if (setupList.size() > 0) { Element firstSetup = (Element) setupList.get(0); DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy.MM.dd"); firstSetup.setAttribute("dateFrom", SQTime.formatDate(SQTime.toLong(2007, 1, 1), formatter)); firstSetup.setAttribute("dateTo",SQTime.formatDate(SQTime.toLong(2017, 1, 1), formatter)); } // alternatively you can load the new task config from prepared file //Element elNewConfig = XMLUtil.fileToXmlElement(new File("c:/BuildTask2009_2019.xml")); ``` -------------------------------- ### Initialize and Run Optimization Engine Source: https://strategyquant.com/doc/programming-for-sq/running-optimizations-programmatically Initialize the OptimizationEngine with prepared settings and start the optimization process. Listeners can be set to track progress and receive results. ```java OptimizationEngine engine = new OptimizationEngine("CustomCAOptimization", progressEngine, null, "OptimTask", null); // it is initialized with settings prepared above engine.initialize(settings); // sets listener that will be called when the optimization result(s) is ready engine.setNewResultListener(new INewResultListener() { public void newResult(ResultsGroup resultsGroup) throws Exception { processResult(resultsGroup, strategyToOptimize.getName(), targetDatabank, dontSaveOriginalStr); } }); // set other listeners that can be ignored for now. // You could use these listeners to track the optimization progress and messages engine.setLogListener(new IEngineLogListener() { public void processMessage(String message) { Log.debug(message); } }); engine.setStepsListener(new IStepsListener() { @Override public void step(int stepNumber) { } }); // start the optimization - method will finish after the optimization fully finished engine.optimize(); ``` -------------------------------- ### Initialize Custom Overview Tab Snippet Source: https://strategyquant.com/doc/quantanalyzer/add-new-statistical-value The constructor sets the snippet's name, screenshot, and HTML template. This example reuses the 'sqdefault_screenshot.jpg' and 'sqdefault_template.htm' from the SQDefault snippet. ```java public DefaultPlusVRatio() { setName("DefaultPlusVRatio"); // we'll copy the values below from SQDefault snippet, our new snippet will use the same HTML template // These files are located in /settings/plugins/OverviewTab setScreenshotName("sqdefault_screenshot.jpg"); setHtmlTemplateName("sqdefault_template.htm"); } ``` -------------------------------- ### Modify Task Configuration and Apply Changes Source: https://strategyquant.com/doc/programming-for-sq/changing-task-config-programmatically This snippet demonstrates how to get a task, clone its configuration, modify specific elements (like date ranges within setups), and then apply the new configuration back to the task. It also includes code to notify the UI about the changes. ```java public CAChangeTaskConfig() { super("CAChangeTaskConfig", TYPE_PROCESS_DATABANK); } @Override public ArrayList processDatabank(String project, String task, String databankName, ArrayList databankRG) throws Exception { // get current project SQProject sqProject = ProjectEngine.get(project); // get task by name ISQTask buildTask = sqProject.getTaskByName("Build strategies"); if(buildTask == null) { throw new Exception("No such task exists!"); } // alternatively you can use sqProject.getTasks() to get a list of all tasks // and go through them to get the one you want // this is how you get task settings XML in the new way (SQ 136 up) // It returns JDOM XML Element with full task configuration Element elConfig = buildTask.getConfig(); // create a new config by cloning it - it is important to make a clone, // otherwise your new config will be not applied Element elNewConfig = elConfig.clone(); // now change anything in the new config Element data = XMLUtil.getChildElem(elNewConfig, "Data"); Element setups = data.getChild("Setups"); List setupList = setups.getChildren("Setup"); if (setupList.size() > 0) { Element firstSetup = (Element) setupList.get(0); DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy.MM.dd"); firstSetup.setAttribute("dateFrom", SQTime.formatDate(SQTime.toLong(2007, 1, 1), formatter)); firstSetup.setAttribute("dateTo",SQTime.formatDate(SQTime.toLong(2017, 1, 1), formatter)); } // alternatively you can load the new task config from prepared file //Element elNewConfig = XMLUtil.fileToXmlElement(new File("c:/BuildTask2009_2019.xml")); // Apply the modified config to the task buildTask.setConfig(elNewConfig, true); // this notifies UI to load che changed config and apply it to the UI. // Without this it would still work but you'll not see the changes in the UI JSONObject jsonData = new JSONObject().put("projectConfig", sqProject.toJSON()); DataToSend dataToSend = new DataToSend(WebSocketConst.UpdateProject, jsonData); SQWebSocketManager.addToDataQueue(dataToSend, SQConst.CODE_TASKMANAGER); return databankRG; } } ``` -------------------------------- ### Profit Factor Tooltip Example Source: https://strategyquant.com/doc/strategyquant/results-plugins Provides an example of a tooltip for the 'Profit Factor' metric. It includes a definition, weak/OK/good thresholds, and a practical example of interpretation. ```plaintext Profit Factor = gross profit ÷ gross loss. Weak: <1.2 · OK: 1.2–1.5 · Good: 1.5+. Example: 1.87 means you earn $1.87 for every $1 lost. ``` -------------------------------- ### Programmatic Backtest Setup and Execution Source: https://strategyquant.com/doc/programming-for-sq/running-strategy-backtests-programmatically This Java code demonstrates how to set up and run a backtest programmatically. It involves configuring chart settings, preparing backtest parameters, selecting a trading simulator, and executing the backtest engine. ```java package 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.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 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 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; } // get first strategy in databank to perform retest on it ResultsGroup strategyToRetest = databankRG.get(0); // we'll store all settings for new backtest in this SettingsMap SettingsMap settings = new SettingsMap(); // prepare chart setup for backtest - you must specify the data name, range, etc ChartSetup chartSetup = new ChartSetup( "History", // this is constant "EURUSD_M1", // symbol name, must match the name in Data Manager TimeframeManager.TF_H1, // timeframe SQTimeOld.toLong(2008, 4, 20), // date from SQTimeOld.toLong(2009, 6, 29), // date to 3.5, // spread Session.Forex_247 // session ); settings.set(SettingsKeys.BacktestChart, chartSetup); // prepare other backtest settings - this will put other optional/required parts to the settings map prepareBacktestSettings(settings, strategyToRetest); // create trading simulator (later used for backtest engine) ITradingSimulator simulator = new MetaTrader4Simulator(); // simulators available: //MetaTrader4Simulator() //MetaTrader5SimulatorHedging(OrderExecutionTypes.EXCHANGE) //MetaTrader5SimulatorNetting(OrderExecutionTypes.EXCHANGE) //TradestationSimulator() //MultiChartsSimulator() //JForexSimulator() // set testing precision for the simulator simulator.setTestPrecision(Precisions.getPrecision(Precisions.PRECISION_BASE_TF)); // Precisions available (depending also on data - you cannot use tick precision if you don't have tick data): //PRECISION_SELECTED_TF = "1 minute data tick simulation (fast)"; //PRECISION_BASE_TF = "1 minute data tick simulation (slow)"; //PRECISION_TICK_CUSTOM_SPREADS = "Real Tick - custom spread (slowest)"; //PRECISION_TICK_REAL_SPREADS = "Real Tick - real spread (slowest)"; //PRECISION_OPEN_PRICES = "Trade On Bar Open"; // create backtest engine using simulator BacktestEngine backtestEngine = new BacktestEngine(simulator); backtestEngine.setSingleThreaded(true); // add backtest settings to the engine backtestEngine.addSetup(settings); // ------------------------ // run backtest - this will run the actual backtest using the settings configured above // Depending on the settings it could take a while. // When finished, it will return new ResultsGroup object with backtest result. // In case of error an Exception is thrown with the description of the error ResultsGroup backtestResultRG = backtestEngine.runBacktest().getResults(); // get backtest result details - here you can access all the results in ResultsGroup // and do something with them. // You can generally do two things: // 1. Get the metrics values and compare / filter them in some way, example: 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); // now do something with these values // For example - you can use the result of this custom backtest t filter out this particular strategy // from databank - ``` -------------------------------- ### Settings for Simple Optimization Source: https://strategyquant.com/doc/programming-for-sq/running-optimizations-programmatically Configuration for a 'Simple' optimization type using the 'BruteForce' method. This is a basic setup for exploring parameter spaces. ```java /** * Optimization settings for Simple optimization */ private OptimizationSettings createOptimizationSettingsSimple(ParametersSettings paramSettings, boolean dontSaveOriginalStr) { OptimizationSettings optimizationSettings = new OptimizationSettings("CustomCAOptimization"); optimizationSettings.type = OptimizationTypes.Simple; optimizationSettings.optimizationMethod = OptimizationMethods.BruteForce; // or OptimizationMethods.GeneticOptimization ``` -------------------------------- ### Prepare Settings for Optimization Source: https://strategyquant.com/doc/programming-for-sq/running-optimizations-programmatically Configures standard backtesting and optimization settings, including strategy details, fitness function, trading options, and chart setup. This is used to prepare the final SettingsMap for an optimization run. ```java OptimizationSettings optimizationSettings = createOptimizationSettingsWF(paramSettings, dontSaveOriginalStr); SettingsMap settings = new SettingsMap(); settings.set(SettingsKeys.TestPrecision, Precisions.SelectedTF); settings.set(SettingsKeys.StrategyXml, elStrategyXml); settings.set(SettingsKeys.StrategyObject, xmlS); settings.set(SettingsKeys.StrategyName, strategyToOptimize.getName()); settings.set(SettingsKeys.FitnessFunction, fitnessFunction); settings.set(SettingsKeys.TradingOptions, tradingOptions.getClone()); settings.set(SettingsKeys.ATM, null); settings.set(SettingsKeys.InitialCapital, 100000d); settings.set(SettingsKeys.Slippage, 0d); settings.set(SettingsKeys.MinimumDistance, 0d); ChartSetup chartSetup = new ChartSetup( "History", "GBPUSD_M1", TimeframeManager.TF_H1, SQTimeOld.toLong(2008, 1, 1), SQTimeOld.toLong(2018, 12, 31), 3, Session.Forex_247); chartSetup.setTestPrecision(settings.getInt(SettingsKeys.TestPrecision)); chartSetup.setBacktestEngine(Engines.MetaTrader4); ChartSetups chartSetups = new ChartSetups(); chartSetups.add((ChartSetup) chartSetup); settings.set(SettingsKeys.BacktestChart, chartSetup); settings.set(SettingsKeys.ChartSetups, chartSetups); settings.set(SettingsKeys.OptimizationSettings, optimizationSettings); settings.set(SettingsKeys.DateGenerated, strategyToOptimize.specialValues().getLong(SpecialValues.DateGenerated, -1)); return settings; ``` -------------------------------- ### Perform Optimization Programmatically Source: https://strategyquant.com/doc/programming-for-sq/running-optimizations-programmatically This snippet demonstrates the core logic for initiating an optimization process programmatically. It involves creating settings, an optimization engine, and listeners for results and logs, then starting the optimization. ```java public void CAOptimizationByProgramming(ResultsGroup strategyToOptimize, String targetDatabank, boolean dontSaveOriginalStr) throws Exception { // here is where you define type of optimization (simple, WF, WFM), parameters range and such SettingsMap settings = prepareSettings(strategyToOptimize, dontSaveOriginalStr); // create required progress engine - although we'll not really use it in Custom analysis snippet ProgressEngine progressEngine = new ProgressEngine("CAOptimizationByProgramming"); // ----------- The optimization engine is used to perform the optimization // first OptimizationEngine object is created OptimizationEngine engine = new OptimizationEngine("CustomCAOptimization", progressEngine, null, "OptimTask", null); // it is initialized with settings prepared above engine.initialize(settings); // sets listener that will be called when the optimization result(s) is ready engine.setNewResultListener(new INewResultListener() { public void newResult(ResultsGroup resultsGroup) throws Exception { processResult(resultsGroup, strategyToOptimize.getName(), targetDatabank, dontSaveOriginalStr); } }); // set other listeners that can be ignored for now. // You could use these listeners to track the optimization progress and messages engine.setLogListener(new IEngineLogListener() { public void processMessage(String message) { Log.debug(message); } }); engine.setStepsListener(new IStepsListener() { @Override public void step(int stepNumber) { } }); // start the optimization - method will finish after the optimization fully finished engine.optimize(); } ``` -------------------------------- ### Get Number of Steps Source: https://strategyquant.com/doc/programming-for-sq/running-optimizations-programmatically A utility method to calculate the total number of steps between a start and stop value given a specific step size. This is used in step calculation logic. ```Java private int getStepsCount(double start, double stop, double step){ return (int)((stop - start) / step); } ``` -------------------------------- ### Configure and Run Backtest Programmatically Source: https://strategyquant.com/doc/programming-for-sq/running-strategy-backtests-programmatically This snippet demonstrates how to set up chart and backtest settings, create a trading simulator and backtest engine, and execute a backtest. It also shows how to retrieve and log basic statistics like the number of trades and net profit from the results. ```Java if(databankRG.size() == 0) { return databankRG; } // get first strategy in databank to perform retest on it ResultsGroup strategyToRetest = databankRG.get(0); // we'll store all settings for new backtest in this SettingsMap SettingsMap settings = new SettingsMap(); // prepare chart setup for backtest - you must specify the data name, range, etc ChartSetup chartSetup = new ChartSetup( "History", // this is constant "EURUSD_M1", // symbol name, must match the name in Data Manager TimeframeManager.TF_H1, // timeframe SQTimeOld.toLong(2008, 4, 20), // date from SQTimeOld.toLong(2009, 6, 29), // date to 3.5, // spread Session.Forex_247 // session ); settings.set(SettingsKeys.BacktestChart, chartSetup); // prepare other backtest settings - this will put other optional/required parts to the settings map prepareBacktestSettings(settings, strategyToRetest); // create trading simulator (later used for backtest engine) ITradingSimulator simulator = new MetaTrader4Simulator(); // simulators available: //MetaTrader4Simulator() //MetaTrader5SimulatorHedging(OrderExecutionTypes.EXCHANGE) //MetaTrader5SimulatorNetting(OrderExecutionTypes.EXCHANGE) //TradestationSimulator() //MultiChartsSimulator() //JForexSimulator() // set testing precision for the simulator simulator.setTestPrecision(Precisions.getPrecision(Precisions.PRECISION_BASE_TF)); // Precisions available (depending also on data - you cannot use tick precision if you don't have tick data): //PRECISION_SELECTED_TF = "Selected timeframe only (fastest)"; //PRECISION_BASE_TF = "1 minute data tick simulation (slow)"; //PRECISION_TICK_CUSTOM_SPREADS = "Real Tick - custom spread (slowest)"; //PRECISION_TICK_REAL_SPREADS = "Real Tick - real spread (slowest)"; //PRECISION_OPEN_PRICES = "Trade On Bar Open"; // create backtest engine using simulator BacktestEngine backtestEngine = new BacktestEngine(simulator); backtestEngine.setSingleThreaded(true); // add backtest settings to the engine backtestEngine.addSetup(settings); // ------------------------ // run backtest - this will run the actual backtest using the settings configured above // Depending on the settings it could take a while. // When finished, it will return new ResultsGroup object with backtest result. // In case of error an Exception is thrown with the description of the error ResultsGroup backtestResultRG = backtestEngine.runBacktest().getResults(); // get backtest result details - here you can access all the results in ResultsGroup // and do something with them. // You can generally do two things: // 1. Get the metrics values and compare / filter them in some way, example: 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); // now do something with these values // For example - you can use the result of this custom backtest t filter out this particular strategy // from databank - by removing it from databankRG array Log.info("Trades: {}, profit: {}", trades, profit); // 2. You can save the new backtest to a databank or 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("Target databank 'Results' was not found!"); } // add the new strategy+backtest to this databank and refresh the databank grid targetDB.add(backtestResultRG, true); // method must return a list of original strategies in databank that passed this filter return databankRG; } ``` ```Java private void prepareBacktestSettings(SettingsMap settings,ResultsGroup strategyToRetest) throws Exception { // creates strategy object from strategy XML that is stored in the source ResultsGroup String strategyName = strategyToRetest.getName(); Element elStrategy = strategyToRetest.getStrategyXml(); if(elStrategy == null) { // result doesn't have any strategy, cannot be tested ``` -------------------------------- ### Java HTTP Request to Python Script Source: https://strategyquant.com/doc/programming-for-sq/calling-python-from-sq-java-introduction This Java code demonstrates how to establish an HTTP GET request to a Python script running on localhost:9000. It handles connection setup, request properties, response retrieval, and basic response processing, including removing HTML tags and storing a substring of the output. ```Java package SQ.CustomAnalysis; import com.strategyquant.lib.SQUtils; import com.strategyquant.lib.app.MainApp; import com.strategyquant.tradinglib.CustomAnalysisMethod; import com.strategyquant.tradinglib.ResultsGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.SimpleScriptContext; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.util.List; public class CAPythonHttp extends CustomAnalysisMethod { public static final Logger Log = LoggerFactory.getLogger(CAPythonHttp.class); //------------------------------------------------------------------------ //------------------------------------------------------------------------ //------------------------------------------------------------------------ public CAPythonHttp() { super("CAJythonScript", TYPE_FILTER_STRATEGY); } //------------------------------------------------------------------------ @Override public boolean filterStrategy(String project, String task, String databankName, ResultsGroup rg) throws Exception { HttpURLConnection connection = null; try { Log.info("Calling Python via HTTP"); URL url = new URL("http://localhost:9000"); connection = (HttpURLConnection)url.openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("Content-Type", "text/html"); connection.setRequestProperty("Content-Language", "en-US"); connection.setUseCaches(false); connection.setDoOutput(true); // get response InputStream is = connection.getInputStream(); BufferedReader rd = new BufferedReader(new InputStreamReader(is)); StringBuilder response = new StringBuilder(); // or StringBuffer if not Java 5+ String line; while((line = rd.readLine()) != null) { response.append(line); response.append('\r'); } rd.close(); String result = response.toString(); // remove HTML tags from response result = result.replaceAll("\\<.*?\\>", ""); Log.info("PythonHTTP script output: "+result); // we'll store only first 10 characters of the result rg.specialValues().set("PythonOutput", result.substring(0, 10)); } catch (Exception e) { throw new Exception("Request error: GET, " + e.getMessage()); } finally { if(connection != null) { connection.disconnect(); } } return true; } } ``` -------------------------------- ### Programmatic Backtest Setup and Execution Source: https://strategyquant.com/doc/programming-for-sq/running-strategy-backtests-programmatically This snippet demonstrates how to set up and run a backtest programmatically. It involves configuring chart settings, preparing backtest parameters, initializing a trading simulator, and executing the backtest engine. Use this when you need to automate backtesting within a custom Java application or script. ```java package 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.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 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 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; } // get first strategy in databank to perform retest on it ResultsGroup strategyToRetest = databankRG.get(0); // we'll store all settings for new backtest in this SettingsMap SettingsMap settings = new SettingsMap(); // prepare chart setup for backtest - you must specify the data name, range, etc ChartSetup chartSetup = new ChartSetup( "History", // this is constant "EURUSD_M1", // symbol name, must match the name in Data Manager TimeframeManager.TF_H1, // timeframe SQTimeOld.toLong(2008, 4, 20), // date from SQTimeOld.toLong(2009, 6, 29), // date to 3.5, // spread Session.Forex_247 // session ); settings.set(SettingsKeys.BacktestChart, chartSetup); // prepare other backtest settings - this will put other optional/required parts to the settings map prepareBacktestSettings(settings, strategyToRetest); // create trading simulator (later used for backtest engine) ITradingSimulator simulator = new MetaTrader4Simulator(); // simulators available: //MetaTrader4Simulator() //MetaTrader5SimulatorHedging(OrderExecutionTypes.EXCHANGE) //MetaTrader5SimulatorNetting(OrderExecutionTypes.EXCHANGE) //TradestationSimulator() //MultiChartsSimulator() //JForexSimulator() // set testing precision for the simulator simulator.setTestPrecision(Precisions.getPrecision(Precisions.PRECISION_BASE_TF)); // Precisions available (depending also on data - you cannot use tick precision if you don't have tick data): //PRECISION_SELECTED_TF = "Selected timeframe only (fastest)"; //PRECISION_BASE_TF = "1 minute data tick simulation (slow)"; //PRECISION_TICK_CUSTOM_SPREADS = "Real Tick - custom spread (slowest)"; //PRECISION_TICK_REAL_SPREADS = "Real Tick - real spread (slowest)"; //PRECISION_OPEN_PRICES = "Trade On Bar Open"; // create backtest engine using simulator BacktestEngine backtestEngine = new BacktestEngine(simulator); backtestEngine.setSingleThreaded(true); // add backtest settings to the engine backtestEngine.addSetup(settings); // ------------------------ // run backtest - this will run the actual backtest using the settings configured above // Depending on the settings it could take a while. // When finished, it will return new ResultsGroup object with backtest result. // In case of error an Exception is thrown with the description of the error ResultsGroup backtestResultRG = backtestEngine.runBacktest().getResults(); // get backtest result details - here you can access all the results in ResultsGroup // and do something with them. // You can generally do two things: // 1. Get the metrics values and compare / filter them in some way, example: 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); // now do something with these values return databankRG; } } ``` -------------------------------- ### Start Method Implementation Source: https://strategyquant.com/doc/programming-for-sq/example-plugin-a-complete-custom-project-task The start() method is the entry point for the task when the 'Start' button is clicked. It initializes settings and the progress engine. ```java public void start() throws Exception { loadSettings(); ``` -------------------------------- ### Prepare Backtest Settings Source: https://strategyquant.com/doc/programming-for-sq/running-strategy-backtests-programmatically Configures backtest settings, including strategy object, initial capital, and money management. Requires a ResultsGroup containing strategy XML. ```java String strategyName = strategyToRetest.getName(); Element elStrategy = strategyToRetest.getStrategyXml(); if(elStrategy == null) { throw new Exception("Result doesn't have any strategy, cannot be tested!"); } StrategyBase strategy = StrategyBase.createXmlStrategy(elStrategy.clone(), strategyName); settings.set(SettingsKeys.StrategyObject, strategy); settings.set(SettingsKeys.MinimumDistance, 0); settings.set(SettingsKeys.InitialCapital, 100000d); settings.set(SettingsKeys.MoneyManagement, MoneyManagementMethodsList.create("FixedSize", 0.1)); ``` -------------------------------- ### Calculate Number of Steps Between Start and Stop Source: https://strategyquant.com/doc/programming-for-sq/running-optimizations-programmatically Calculates the number of steps between a start and stop value given a specific step size. This is a utility function used in step calculation logic. ```Java private int getStepsCount(double start, double stop, double step){ return (int)((stop - start) / step); } ``` -------------------------------- ### Progress Engine Initialization Source: https://strategyquant.com/doc/programming-for-sq/example-plugin-a-complete-custom-project-task Initializes and starts the progress engine for the task. This provides feedback during the execution of the filtering process. ```java progressEngine.setLogPrefix(taskLogPrefix); progressEngine.printToLog(L.t("Starting strategies filtering...")); progressEngine.start(); ``` -------------------------------- ### Prepare Optimization Settings Source: https://strategyquant.com/doc/programming-for-sq/running-optimizations-programmatically Configures essential settings for the OptimizationEngine, including initial capital, slippage, and minimum distance. It also prepares chart setup details for backtesting, specifying the instrument, timeframe, date range, and backtest engine. ```java settings.set(SettingsKeys.InitialCapital, 100000d); settings.set(SettingsKeys.Slippage, 0d); settings.set(SettingsKeys.MinimumDistance, 0d); // prepare chart setup for backtest ChartSetup chartSetup = new ChartSetup( "History", "GBPUSD_M1", TimeframeManager.TF_H1, SQTimeOld.toLong(2008, 1, 1), SQTimeOld.toLong(2018, 12, 31), 3, Session.Forex_247); chartSetup.setTestPrecision(settings.getInt(SettingsKeys.TestPrecision)); chartSetup.setBacktestEngine(Engines.MetaTrader4); ChartSetups chartSetups = new ChartSetups(); chartSetups.add((ChartSetup) chartSetup); settings.set(SettingsKeys.BacktestChart, chartSetup); settings.set(SettingsKeys.ChartSetups, chartSetups); //OptimizationSettings jobOptimizationSettings = optimizationSettings.clone(); settings.set(SettingsKeys.OptimizationSettings, optimizationSettings); settings.set(SettingsKeys.DateGenerated, strategyToOptimize.specialValues().getLong(SpecialValues.DateGenerated, -1)); return settings; } catch(Exception e){ throw new Exception("Error while preparing settings - " + e.getMessage(), e); } } ``` -------------------------------- ### Get Strategy Base Source: https://strategyquant.com/doc/programming-for-sq/viewing-and-changing-strategy-parameters-version-2 Helper method to create and transform a StrategyBase object from a ResultsGroup. Used internally by other methods. ```java private static StrategyBase getStrategyBase(ResultsGroup rg, boolean symmetricVariables) throws Exception { StrategyBase xmlS = StrategyBase.createXmlStrategy(rg.getStrategyXml()); xmlS.transformToVariables(symmetricVariables); return xmlS; } } ``` -------------------------------- ### Configure Strategy Settings for Backtesting Source: https://strategyquant.com/doc/programming-for-sq/running-strategy-backtests-programmatically Sets up essential parameters for a strategy backtest, including the strategy object, initial capital, and money management method. Ensure the strategy XML is valid and the MoneyManagementMethodsList is correctly specified. ```Java StrategyBase strategy = StrategyBase.createXmlStrategy(elStrategy.clone(), strategyName); settings.set(SettingsKeys.StrategyObject, strategy); settings.set(SettingsKeys.MinimumDistance, 0); // set initial capital and Money management settings.set(SettingsKeys.InitialCapital, 100000d); settings.set(SettingsKeys.MoneyManagement, MoneyManagementMethodsList.create("FixedSize", 0.1)); // Note - you can create a different Money Managemtn method by specifying its (snippet) name // and parameters in their exact order, for example: // MoneyManagementMethodsList.create("RiskFixedPctOfAccount", 5, 100, 0.1, 0.5)) ``` -------------------------------- ### Prepare Settings for OptimizationEngine Source: https://strategyquant.com/doc/programming-for-sq/running-optimizations-programmatically This method prepares all necessary settings for the OptimizationEngine, including parameter ranges, fitness functions, trading options, and chart configurations. It returns a SettingsMap object containing all configurations. ```java private SettingsMap prepareSettings(ResultsGroup strategyToOptimize, boolean dontSaveOriginalStr) throws Exception { try { // create parameter settings - configures ranges for optimized parameters ParametersSettings paramSettings = createParametersSettings(strategyToOptimize); // get strategy XML and create strategy object from XML with variables for parameters Element elStrategyXml = strategyToOptimize.getStrategyXml(); StrategyBase xmlS = StrategyBase.createXmlStrategy(elStrategyXml); xmlS.transformToVariables(paramSettings.symmetry, paramSettings.paramTypes); // create fitness function and trading options used in optimization IFitnessFunction fitnessFunction = createFitnessFunction(); TradingOptions tradingOptions = createTradingOptions(); // applies parameter settings to strategy variables applyParamSettingsToStrategy(paramSettings, xmlS, tradingOptions); // creates optimization setting - simple, WF? steps etc. - look at the method for the correct parameters //OptimizationSettings optimizationSettings = createOptimizationSettingsSimple(paramSettings, dontSaveOriginalStr); OptimizationSettings optimizationSettings = createOptimizationSettingsWF(paramSettings, dontSaveOriginalStr); //OptimizationSettings optimizationSettings = createOptimizationSettingsWFM(paramSettings, dontSaveOriginalStr); // creates final SettingsMap to return SettingsMap settings = new SettingsMap(); // standard backtesting settings settings.set(SettingsKeys.TestPrecision, Precisions.SelectedTF); settings.set(SettingsKeys.StrategyXml, elStrategyXml); settings.set(SettingsKeys.StrategyObject, xmlS); settings.set(SettingsKeys.StrategyName, strategyToOptimize.getName()); settings.set(SettingsKeys.FitnessFunction, fitnessFunction); settings.set(SettingsKeys.TradingOptions, tradingOptions.getClone()); settings.set(SettingsKeys.ATM, null); settings.set(SettingsKeys.InitialCapital, 100000d); settings.set(SettingsKeys.Slippage, 0d); settings.set(SettingsKeys.MinimumDistance, 0d); // prepare chart setup for backtest ChartSetup chartSetup = new ChartSetup( "History", "GBPUSD_M1", TimeframeManager.TF_H1, SQTimeOld.toLong(2008, 1, 1), SQTimeOld.toLong(2018, 12, 31), 3, Session.Forex_247); chartSetup.setTestPrecision(settings.getInt(SettingsKeys.TestPrecision)); chartSetup.setBacktestEngine(Engines.MetaTrader4); ChartSetups chartSetups = new ChartSetups(); chartSetups.add((ChartSetup) chartSetup); settings.set(SettingsKeys.BacktestChart, chartSetup); settings.set(SettingsKeys.ChartSetups, chartSetups); //OptimizationSettings jobOptimizationSettings = optimizationSettings.clone(); settings.set(SettingsKeys.OptimizationSettings, optimizationSettings); settings.set(SettingsKeys.DateGenerated, strategyToOptimize.specialValues().getLong(SpecialValues.DateGenerated, -1)); return settings; } catch(Exception e){ throw new Exception("Error while preparing settings - " + e.getMessage(), e); } } ``` -------------------------------- ### Get Strategy Parameter Value Source: https://strategyquant.com/doc/programming-for-sq/viewing-and-changing-strategy-parameters-version-2 Retrieves the value of a specific strategy parameter. Handles cases where the parameter might not exist. ```java public static String getParameterValue(ResultsGroup rg, boolean symmetricVariables, String parameterName) throws Exception { StrategyBase strategyBase = getStrategyBase(rg, symmetricVariables); Variables variables = strategyBase.variables(); Variable variable = variables.get(parameterName); if(variable == null) return null; return variable.getValue(); } ``` -------------------------------- ### Get Output Folder Path Source: https://strategyquant.com/doc/programming-for-sq/save-databank-results-to-db Returns the configured path for saving databank export files. Ensure this directory exists. ```Java return "C:/SQDatabankExports"; ``` -------------------------------- ### Prepare Settings for Optimization Engine Source: https://strategyquant.com/doc/programming-for-sq/running-optimizations-programmatically This method prepares the necessary settings for the OptimizationEngine, including strategy parameters, fitness functions, trading options, and backtesting configurations. ```java private SettingsMap prepareSettings(ResultsGroup strategyToOptimize, boolean dontSaveOriginalStr) throws Exception { try { // create parameter settings - configures ranges for optimized parameters ParametersSettings paramSettings = createParametersSettings(strategyToOptimize); // get strategy XML and create strategy object from XML with variables for parameters Element elStrategyXml = strategyToOptimize.getStrategyXml(); StrategyBase xmlS = StrategyBase.createXmlStrategy(elStrategyXml); xmlS.transformToVariables(paramSettings.symmetry, paramSettings.paramTypes); // create fitness function and trading options used in optimization IFitnessFunction fitnessFunction = createFitnessFunction(); TradingOptions tradingOptions = createTradingOptions(); // applies parameter settings to strategy variables applyParamSettingsToStrategy(paramSettings, xmlS, tradingOptions); // creates optimization setting - simple, WF? steps etc. - look at the method for the correct parameters //OptimizationSettings optimizationSettings = createOptimizationSettingsSimple(paramSettings, dontSaveOriginalStr); OptimizationSettings optimizationSettings = createOptimizationSettingsWF(paramSettings, dontSaveOriginalStr); //OptimizationSettings optimizationSettings = createOptimizationSettingsWFM(paramSettings, dontSaveOriginalStr); // creates final SettingsMap to return SettingsMap settings = new SettingsMap(); // standard backtesting settings settings.set(SettingsKeys.TestPrecision, Precisions.SelectedTF); settings.set(SettingsKeys.StrategyXml, elStrategyXml); settings.set(SettingsKeys.StrategyObject, xmlS); settings.set(SettingsKeys.StrategyName, strategyToOptimize.getName()); settings.set(SettingsKeys.FitnessFunction, fitnessFunction); settings.set(SettingsKeys.TradingOptions, tradingOptions.getClone()); settings.set(SettingsKeys.ATM, null); settings.set(SettingsKeys.InitialCapital, 100000d); settings.set(SettingsKeys.Slippage, 0d); settings.set(SettingsKeys.MinimumDistance, 0d); // prepare chart setup for backtest ChartSetup chartSetup = new ChartSetup( "History", "GBPUSD_M1", TimeframeManager.TF_H1, SQTimeOld.toLong(2008, 1, 1), SQTimeOld.toLong(2018, 12, 31), 3, Session.Forex_247); chartSetup.setTestPrecision(settings.getInt(SettingsKeys.TestPrecision)); chartSetup.setBacktestEngine(Engines.MetaTrader4); ChartSetups chartSetups = new ChartSetups(); chartSetups.add((ChartSetup) chartSetup); settings.set(SettingsKeys.BacktestChart, chartSetup); settings.set(SettingsKeys.ChartSetups, chartSetups); //OptimizationSettings jobOptimizationSettings = optimizationSettings.clone(); settings.set(SettingsKeys.OptimizationSettings, optimizationSettings); settings.set(SettingsKeys.DateGenerated, strategyToOptimize.specialValues().getLong(SpecialValues.DateGenerated, -1)); return settings; } catch(Exception e){ throw new Exception("Error while preparing settings - " + e.getMessage(), e); } } ``` -------------------------------- ### Prepare Optimization Settings Source: https://strategyquant.com/doc/programming-for-sq/running-optimizations-programmatically Prepare the necessary settings for optimization. This method should be called before initializing the OptimizationEngine. ```java SettingsMap settings = prepareSettings(strategyToOptimize, dontSaveOriginalStr); ``` -------------------------------- ### Get Strategy Parameter Value Source: https://strategyquant.com/doc/programming-for-sq/viewing-and-changing-strategy-parameters-version-2 Retrieves the value of a specific strategy parameter by name. Ensure the ResultsGroup and parameterName are correctly provided. ```java public static String getParameterValue(ResultsGroup rg, boolean symmetricVariables, String parameterName) throws Exception { StrategyBase strategyBase = getStrategyBase(rg, symmetricVariables); Variables variables = strategyBase.variables(); Variable variable = variables.get(parameterName); if(variable == null) return null; return variable.getValue(); } ``` -------------------------------- ### Create Optimization Settings for Walk-Forward Matrix Optimization Source: https://strategyquant.com/doc/programming-for-sq/running-optimizations-programmatically Configures settings for Walk-Forward Matrix optimization using Brute Force method. It defines ranges for two parameters and sets the period in percentage. ```java private OptimizationSettings createOptimizationSettingsWFM(ParametersSettings paramSettings, boolean dontSaveOriginalStr) { OptimizationSettings optimizationSettings = new OptimizationSettings("CustomCAOptimization"); optimizationSettings.type = OptimizationTypes.WalkForwardMatrix; optimizationSettings.optimizationMethod = OptimizationMethods.BruteForce; optimizationSettings.optimizationType = OptimizationConst.WF_TYPE_SIMIS_EXACTOOS; optimizationSettings.maxOptimizationBacktests = 1000; // max optimizations limit as in UI optimizationSettings.parameters = paramSettings.params; optimizationSettings.dontSaveOriginalStr = dontSaveOriginalStr; optimizationSettings.periodInPercent = true; optimizationSettings.param1Start = 20; optimizationSettings.param1Stop = 40; optimizationSettings.param1Step = 10; optimizationSettings.param2Start = 5; optimizationSettings.param2Stop = 20; optimizationSettings.param2Step = 5; return optimizationSettings; } ``` -------------------------------- ### Get strategy parameter names Source: https://strategyquant.com/doc/programming-for-sq/viewing-and-changing-strategy-parameters-version-2 Retrieves a list of all parameter names for a given strategy. This is useful for understanding the configurable options of a strategy. ```Java public static ArrayList getParameterNames(ResultsGroup rg, ValuesMap parameterTypes, boolean symmetricVariables) throws Exception { HashMap paramsMap = getParameterValues(rg, parameterTypes, symmetricVariables); ArrayList list = new ArrayList<>(); list.addAll(paramsMap.keySet()); return list; } ``` -------------------------------- ### Walk-Forward Optimization Settings Source: https://strategyquant.com/doc/programming-for-sq/running-optimizations-programmatically Configures settings for Walk-Forward optimization. This method is suitable for strategies that adapt to changing market conditions over time. ```java private OptimizationSettings createOptimizationSettingsWF(ParametersSettings paramSettings, boolean dontSaveOriginalStr) { OptimizationSettings optimizationSettings = new OptimizationSettings("CustomCAOptimization"); optimizationSettings.type = OptimizationTypes.WalkForward; optimizationSettings.optimizationMethod = OptimizationMethods.GeneticOptimization; //OptimizationMethods.BruteForce; optimizationSettings.optimizationType = OptimizationConst.WF_TYPE_SIMIS_EXACTOOS; optimizationSettings.maxOptimizationBacktests = 1000; // max optimizations limit as in UI optimizationSettings.parameters = paramSettings.params; optimizationSettings.dontSaveOriginalStr = dontSaveOriginalStr; optimizationSettings.periodInPercent = true; optimizationSettings.param1Start = 20; optimizationSettings.param1Stop = 40; optimizationSettings.param1Step = 10; // param2XXX settings are not used, but must be set properly optimizationSettings.param2Start = 5; optimizationSettings.param2Stop = 20; optimizationSettings.param2Step = 5; return optimizationSettings; } ``` -------------------------------- ### Get strategy base object Source: https://strategyquant.com/doc/programming-for-sq/viewing-and-changing-strategy-parameters-version-2 Internal helper method to create and transform a StrategyBase object from ResultsGroup. It prepares the strategy for variable manipulation. ```Java private static StrategyBase getStrategyBase(ResultsGroup rg, boolean symmetricVariables) throws Exception { StrategyBase xmlS = StrategyBase.createXmlStrategy(rg.getStrategyXml()); xmlS.transformToVariables(symmetricVariables); return xmlS; } ```