Parse strategy XML to extract settings, variables, rules, and parameters including stop loss and profit targets for custom analysis and automation.
Thanks to viewing and changing strategy parameters documentation, we can read strategy variables.
This code example reads strategy XML, variables, and rules.
1. Strategy Overview
• Strategy XML can be read with XMLUtil.elementToString().
Run Custom Analysis XmlStrategyToFile or XmlStrategyToFileSym (symmetrical strategies) to export from Databank to disk. Open XML files in any XML reader like https://jsonformatter.org/xml-editor.

• Strategies have rules and variables.

In SQ.utils.Bouillant extension, function toBuildingBlocksName shows two regions: Variables and Rules.

2. XMLUtil Class and JDOM Element
XMLUtil API Documentation
3. Reading Strategy Variables
Get variable values:
• getVariableValueToBoolean
• getVariableValueToInt
• getVariableValueToDouble
4. Example: Extract Stop Loss and Profit Target
Custom Analysis CA_StrategySettings or CA_StrategySettingsSym:

@Override
public boolean filterStrategy(String project, String task, String databankName, ResultsGroup rg) throws Exception
{
Bouillant BouilltParaObj1 = new Bouillant();
int IntTemp = BouilltParaObj1.getVariableValueToInt(rg, false,"LongProfitTarget");
rg.specialValues().set("CA_Long_ProfitTarget", IntTemp);
IntTemp = BouilltParaObj1.getVariableValueToInt(rg, false,"ShortProfitTarget");
rg.specialValues().set("CA_Short_ProfitTarget", IntTemp);
IntTemp = BouilltParaObj1.getVariableValueToInt(rg, false,"LongStopLoss");
rg.specialValues().set("CA_Long_StopLoss", IntTemp);
IntTemp = BouilltParaObj1.getVariableValueToInt(rg, false,"ShortStopLoss");
rg.specialValues().set("CA_Short_StopLoss", IntTemp);
IntTemp = BouilltParaObj1.getVariableValueToInt(rg, false,"LongTrailingStop");
rg.specialValues().set("CA_Long_TrailingStop", IntTemp);
IntTemp = BouilltParaObj1.getVariableValueToInt(rg, false,"ShortTrailingStop");
rg.specialValues().set("CA_Short_TrailingStop", IntTemp);
return true;
}


5. Reading XML Strategy Step by Step
A. Get root Element:
StrategyBase strategyBase = getStrategyBase(strategyRG, symmetricVariables);
Element Strategie1 = strategyBase.getStrategyXml();
B. Get specific child Element:
Element elParams = Strategie1.getChild("Strategy").getChild("Variables");
elParams = Strategie1.getChild("Strategy").getChild("Rules").getChild("Events");
C. Get children elements to List:
List<Element> paramElems = elParams.getChildren();
D. Read NodeValue:
for (i = 0; i < paramElems.size(); i++) {
Element elParam = paramElems.get(i);
String name = XMLUtil.getNodeValue(elParam,"name");
String id = XMLUtil.getNodeValue(elParam,"id");
}
E. Get AttributeValue:
String elParamKey = elParam.getAttributeValue("key");
F. Convert Element to String:
String String1 = XMLUtil.elementToString(elParam);
6. Application: Calling the Function

DataBank Column snippet:
Bouillant BouilltParaObj1 = new Bouillant();
String StringTotal = BouilltParaObj1.toBuildingBlocksName(results,false, "LongEntrySignal",100);
Select entry/exit signals (LongEntrySignal, ShortEntrySignal, LongExitSignal, ShortExitSignal, etc.).
package SQ.Columns.Databanks;
import SQ.Utils.Bouillant;
import com.strategyquant.lib.L;
import com.strategyquant.tradinglib.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StrategyBuildingBlocks extends DatabankColumn
{
public static final Logger Log = LoggerFactory.getLogger(StrategyBuildingBlocks.class);
public StrategyBuildingBlocks() {
super(L.tsq("Strategy Building Blocks"), DatabankColumn.Text, ValueTypes.Maximize, 0, 0, 1);
setWidth(1000);
}
@Override
public double getNumericValue(ResultsGroup results, String resultKey, byte direction, byte plType, byte sampleType) throws Exception {
return 0;
}
@Override
public String getValue(ResultsGroup results, String resultKey, byte direction, byte plType, byte sampleType) throws Exception
{
try
{
String StringTotal = "";
Bouillant BouilltParaObj1 = new Bouillant();
String String1 = BouilltParaObj1.toBuildingBlocksName(results,false, "LongEntrySignal",100);
BouilltParaObj1 = new Bouillant();
String String2 = BouilltParaObj1.toBuildingBlocksName(results,false, "ShortEntrySignal",100);
if (String1 == null || String2 == null) { return "";}
int maxLength = (String1.length() < 100)?String1.length():100;
String1 = String1.substring(0, maxLength);
maxLength = (String2.length() < 100)?String2.length():100;
String2 = String2.substring(0, maxLength);
if (!String1.equals("") && !String2.equals("")) {
StringTotal += String1 + "," + String2;
} else if (!String1.equals("")) {
StringTotal += String1;
} else if (!String2.equals("")) {
StringTotal += String2;
}
return StringTotal;
} catch(Exception e) {
Log.error("Error StrategyBuildingBlocks", e);
return "";
}
}
}
7. Building Blocks Names in DataBank

8. toBuildingBlocksName Function
Reads variables and rules, returns Building Blocks names:
public String toBuildingBlocksName(ResultsGroup strategyRG, boolean symmetricVariables, String TradingSignalName, int breakdownLevelMax) throws Exception
{
try
{
String SignalID = "";
String strName = strategyRG.getName();
if(strName.startsWith("Filtered portfolio") || strName.startsWith("Portfolio")) { return ""; }
StrategyBase strategyBase = getStrategyBase(strategyRG, symmetricVariables);
Element Strategie1 = strategyBase.getStrategyXml();
if (Strategie1 != null)
{
Element elParams = Strategie1.getChild("Strategy").getChild("Variables");
if (elParams != null)
{
List<Element> paramElems = elParams.getChildren();
VariableValues = new HashMap<String, String>();
VariableID = new HashMap<String, String>();
VariableType = new HashMap<String, String>();
for (int i = 0; i < paramElems.size(); i++)
{
Element elParam = paramElems.get(i);
if (elParam != null)
{
String name = XMLUtil.getNodeValue(elParam,"name");
String id = XMLUtil.getNodeValue(elParam,"id");
String value = XMLUtil.getNodeValue(elParam,"value");
String Type = XMLUtil.getNodeValue(elParam,"type");
VariableID.put(name, id);
VariableValues.put(name, value);
VariableType.put(name, Type);
if (name.equals(TradingSignalName)) { SignalID = id; }
}
}
}
elParams = Strategie1.getChild("Strategy").getChild("Rules").getChild("Events");
if (elParams != null)
{
List<Element> paramElems = elParams.getChildren();
for (int i = 0; i < paramElems.size(); i++)
{
Element elParam2 = paramElems.get(i);
if (elParam2 != null) {
String elParamKey2 = elParam2.getAttributeValue("key");
if (elParamKey2.equals("OnBarUpdate")) {
List<Element> paramElems3 = elParam2.getChildren();
for (int i2 = 0; i2 < paramElems3.size(); i2++) {
Element elParam3 = paramElems3.get(i2);
if (elParam3 != null) {
String elParamKey3 = elParam3.getAttributeValue("name");
if (elParamKey3.equals("Trading signals")) {
Element elParams4 = elParam3.getChild("signals");
List<Element> paramElems4 = elParams4.getChildren();
for (int i3 = 0; i3 < paramElems4.size(); i3++) {
Element elParam4 = paramElems4.get(i3);
if (elParam4 != null) {
String elParamKey4 = elParam4.getAttributeValue("variable");
if (elParamKey4.equals(SignalID)) {
Element elParams5 = elParam4.getChild("Item");
if (elParams5 != null) {
String key = elParams5.getAttributeValue("key");
if (!key.equals("Boolean")) {
ArrayListElemsAll = new ArrayList<Element>();
UpdateNodesValues(strategyRG, symmetricVariables, elParams5, breakdownLevelMax, 0);
AddToList(strategyRG, symmetricVariables, elParams5, breakdownLevelMax, 0);
StringBuilder sb = new StringBuilder();
if (ArrayListElemsAll.size()>=1) {
for (int i5 = 0; i5 < ArrayListElemsAll.size(); i5++) {
Element elParam6Temp = ArrayListElemsAll.get(i5);
if (elParam6Temp != null) {
String elParamKey8Temp = elParam6Temp.getAttributeValue("name");
sb.append(elParamKey8Temp);
sb.append(ParamDelimiter);
}
}
}
return sb.toString();
}
}
}
}
}
}
}
}
}
}
}
}
}
return "";
} catch (Exception e) {
Log.error("Error toBuildingBlocksName", e);
return "";
}
}
9. Recursive Functions: UpdateNodesValues and AddToList
public void UpdateNodesValues(ResultsGroup strategyRG, boolean symmetricVariables, Element element, int breakdownLevelMax, int breakdownLevel) throws Exception
{
if (element != null) {
breakdownLevel++;
List<Element> element1 = element.getChildren();
for (int i = 0; i < element1.size(); i++) {
Element element11 = element1.get(i);
if (element11 != null) { UpdateNodesValues(strategyRG, symmetricVariables, element11, breakdownLevelMax, breakdownLevel); }
}
}
if (element != null) {
List<Element> listParams = element.getChildren("Param");
for (int i = 0; i < listParams.size(); i++) {
Element courant = listParams.get(i);
if (courant != null) {
String elParamKey5 = courant.getAttributeValue("key");
String elParamVariable3 = courant.getAttributeValue("variable");
if (elParamKey5.startsWith("#") && elParamVariable3=="true") {
String Temp1 = VariableValues.get(courant.getText());
if (Temp1 != null) { courant.setText(Temp1); }
}
}
}
}
}
public void AddToList(ResultsGroup strategyRG, boolean symmetricVariables, Element element, int breakdownLevelMax, int breakdownLevel) throws Exception
{
boolean Condition1 = false;
if (element != null) {
breakdownLevel++;
String elParamKey = element.getAttributeValue("key");
String categoryType = element.getAttributeValue("categoryType");
if (categoryType == null) { categoryType = ""; }
if (breakdownLevelMax < 100) { Condition1 = (elParamKey.equals("IsRising") || elParamKey.equals("IsFalling") || elParamKey.equals("IsLowerCount") || elParamKey.equals("IsGreaterCount") || elParamKey.equals("IsLower") || elParamKey.equals("IsLowerOrEqual") || elParamKey.equals("IsGreater") || elParamKey.equals("IsGreaterOrEqual") || elParamKey.equals("CrossesAbove") || elParamKey.equals("CrossesBelow") || elParamKey.startsWith("CBlock")); }
if (!Condition1) {
List<Element> element1 = element.getChildren();
for (int i = 0; i < element1.size(); i++) {
Element element11 = element1.get(i);
if (element11 != null) { AddToList(strategyRG, symmetricVariables, element11, breakdownLevelMax, breakdownLevel); }
}
}
List<Element> listParams = element.getChildren("Param");
if (listParams.size() >= 1 || Condition1) {
Element elementCopy = (Element)element.clone();
elParamKey = elementCopy.getAttributeValue("key");
listParams = elementCopy.getChildren("Param");
List<Element> listParamsBlock = element.getChildren("Block");
if (listParamsBlock.size() == 0 || Condition1) {
if ((listParams.size() == 1 && !elParamKey.equals("Number")) || !elParamKey.equals("Number")) {
if (breakdownLevel <= breakdownLevelMax) { ArrayListElemsAll.add(elementCopy); }
}
}
}
}
}
10. Conclusion
Start by reading XML structure with XMLUtil.elementToString(), then use functions A-F above. Find more at XMLUtil API Documentation.
References: Viewing and Changing Strategy Parameters, W3Schools XML, Java JDOM Parse Document
Author: Emmanuel Bouillant-Evrard, Engineer specialized in Finance with 24 years R&D experience in USA, Canada, and France.