17. 5. 2022

5 4

Reading Strategy settings, variables, rules and building blocks in few easy step using Xml

Thanks to a previous example : https://strategyquant.com/doc/programming-for-sq/viewing-and-changing-strategy-parameters-version-2/, we can read a strategy and its variables.

This code example is going one step further by reading the XML of a strategy, its variables and its rules.

 

1/ Overview of a Strategy

  • A Strategy Xml can be read with the XMLUtil.elementToString() function. 

You can run a Custom Analysis XmlStrategyToFile or XmlStrategyToFileSym (for symmetrical strategies) to transform any strategy from your Databank to your drive to an output path like “C:\Temp

Then you can open this XML file in any xml reader (like https://jsonformatter.org/xml-editor for example.)

You can read a template as well , if you load your template in Databank.

(Please see the attached Custom Project StrategyToXmlFile and the attached Xml of a strategy Strategy 1.6.22(1)B)

 

  • A Strategies have rules and Variables :

If you open the SQ.utils.Bouillant extension, you will find a similar structure to open a strategy:

In “toBuildingBlocksName” function, we can see two regions of the code , Variables and Rules as well

 

2/ We are using XMLUtil Class and JDOM Element

https://strategyquant.com/sqxapi/com/strategyquant/lib/XMLUtil.html

 

3/ How to read strategy variables

Once, we get the XML from a Strategy, we have to get its variables values. They can be Boolean, Integer, or Double.

To get them, you have three functions :

  • getVariableValueToBoolean
  • getVariableValueToInt
  • getVariableValueToDouble

 

From these functions, we can get any variables values from a strategy.

4/ For example,  we can get a Stop loss value or a Profit Target value from the strategy settings and insert the results in a databank :

With this extension, you can find a Custom Analysis “CA_StrategySettings” or “CA_StrategySettingsSym” (for symmetrical strategies)

These Custom Analysis will call SQ.utils.Bouillant extension and request a Stop Loss value or a Profit Target value from a signal :

@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;
}

(As you can see in the attached Custom Project : StrategySettings)

Once you run “CA_StrategySettingscustom analysis or “CA_StrategySettingsSymcustom analysis , you can read a stop loss value or a profit target value from any strategy settings and update your databank with the following snippets :

Here are the Profit Target value and Stop Loss Value from the strategy Settings

 

 

5/ How to read XML Strategy Step by Step

(from our function toBuildingBlocksName in SQ.Utils.Bouillant)

 

A/ Our example is using getStrategyBase function to get the root Element of a strategy :

 

StrategyBase strategyBase = getStrategyBase(strategyRG, symmetricVariables);

Element Strategie1 = strategyBase.getStrategyXml();

 

B/ From the Strategie1 Element, it is getting a specific child Element

 

Element elParams = Strategie1.getChild("Strategy").getChild("Variables");

or

elParams = Strategie1.getChild("Strategy").getChild("Rules").getChild("Events");											// go to Rules section of the Strategy Xml

 

C/ From the elParams Element, it is getting the childrens elements to a List of Elements paramElems

 

List<Element> paramElems = elParams.getChildren();

 

D/ From List of Elements paramElems, you can get each Element and read the NodeValue by using getNodeValue :

 

for (i = 0; i < paramElems.size(); i++) 
{
    Element elParam = paramElems.get(i);

    String name = XMLUtil.getNodeValue(elParam,"name");
    String id = XMLUtil.getNodeValue(elParam,"id");

    if (name.equals(TradingSignalName))   																					// We search the Id of the TradingSignalName, necessary to find the corresponding rule					
    {
        SignalID = id;
    }
}
E/ From List of Elements paramElems, you can get each AttributeValue of an Element :

 

String elParamKey = elParam.getAttributeValue("key");

 

F/ From an Element to a String 

Like for a strategy, if you want to read an Element and look at its structure, you can use the function XMLUtil.elementToString as well and send it to a file.

String String1 = XMLUtil.elementToString(elParam);

 

6/ Application : How to call this function, how to use it .

With this example, we have DataBank Column snippets to apply this function :

Bouillant BouilltParaObj1 = new Bouillant();
String StringTotal = BouilltParaObj1.toBuildingBlocksName(results,false, "LongEntrySignal",100);

 

This function is asking the Building Blocks with a ResultsGroup and a TradingSignal Name. (LongEntrySignal, ShortEntrySignal, LongExitSignal, ShortExitSignal,…)

It is really practical because you can select an Entry Long, or an Entry Short, or an Exit Long or Short signal, or all of them together

You can even select whatever signal name from your template.

Here is the code :

package SQ.Columns.Databanks;

import SQ.Utils.Bouillant;
import com.strategyquant.lib.L;
import com.strategyquant.tradinglib.*;
import com.strategyquant.tradinglib.optimization.WalkForwardMatrixResult;
import com.strategyquant.lib.ValuesMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// Created in France by Emmanuel Bouillant-Evrard for the StrategyQuantX Community :)
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);														// 100 to have the name of Building blocks
            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 "";																																							       // "Error: " + e.getMessage();
        }
    }
}

 

7/ The Building Blocks Name of each Strategy in the DataBank

 

8/ The toBuildingBlocksName function code 

 

/**
     * This Function read the variables name, the rules, then return a String of Building Blocks name. 
     * @param strategyRG
     * @param symmetricVariables
     * @param TradingSignal
     * @return
     */
    public String toBuildingBlocksName(ResultsGroup strategyRG, boolean symmetricVariables, String TradingSignalName, int breakdownLevelMax) throws Exception 
    {
        try 
        {
            int i;
            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 (DebugMode){
            OutputPath = "C:\\Temp\\"+strName+".txt";
            FileWriter myWriter = new FileWriter(OutputPath , true);  }

            if (Strategie1 != null) 
            {
                //#region ********************************************************* Variables **************************************************************************************
                String test4 = "" ;   
                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 (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 (DebugMode){
                            test4 = XMLUtil.getNodeValue(elParam,"name") + "   " +  XMLUtil.getNodeValue(elParam,"id");
                            myWriter.write("name + id : "+ test4 + "\r\n");
                            myWriter.write("VariableID : "+ VariableID.get(name) + "\r\n");

                            test4 = XMLUtil.getNodeValue(elParam,"name") + "   " +  XMLUtil.getNodeValue(elParam,"value");
                            myWriter.write("name + value : "+ test4 + "\r\n");
                            myWriter.write("VariableValues : "+ VariableValues.get(name) + "\r\n");
                            
                            test4 = XMLUtil.getNodeValue(elParam,"name") + "   " +  XMLUtil.getNodeValue(elParam,"type");
                            myWriter.write("name + type : "+ test4 + "\r\n");
                            myWriter.write("VariableType : "+ VariableType.get(name) + "\r\n");}

                            if (name.equals(TradingSignalName))   																					// We search the Id of the TradingSignalName, necessary to find the corresponding rule					
                            {
                                SignalID = id;
                            }
                        }
                    }
                    if (DebugMode){
                    myWriter.close();} 
                }
                //#endregion

                //#region ********************************************************* Rules ******************************************************************************************
                elParams = Strategie1.getChild("Strategy").getChild("Rules").getChild("Events");											// go to Rules section of the Strategy Xml
                if (elParams != null) 
                {
                    List<Element> paramElems = elParams.getChildren(); 
                    for (i = 0; i < paramElems.size(); i++) 
                    {
                        Element elParam2 = paramElems.get(i);

                        if (elParam2 != null) {
                        String elParamKey2 = elParam2.getAttributeValue("key");
                        if (elParamKey2.equals("OnBarUpdate"))												             						// Looks for OnBarUpdate rule
                        {
                            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"))																		// Look for Trading signals rule
                                {
                                    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))																		// Look for the requested TradingSignalName from its ID : SignalID
                                        {
                                            if (DebugMode){
                                            myWriter = new FileWriter(OutputPath , true); 
                                            String String1 = XMLUtil.elementToString(elParam4);
                                            myWriter.write(String1);
                                            myWriter.close();}

                                            Element elParams5 = elParam4.getChild("Item");
                                            
                                            if (DebugMode){	
                                            myWriter = new FileWriter(OutputPath , true); 
                                            String String1 = XMLUtil.elementToString(elParams5);
                                            myWriter.write(String1);
                                            myWriter.close();} 												

                                            if (elParams5 != null) {
                                            String key = elParams5.getAttributeValue("key");					    																		// the name
                                            if (!key.equals("Boolean")) 							  
                                            {
                                                Element elParam5Temp = elParams5;
                                                Element elParam6Temp = elParams5;
                                                strName = strategyRG.getName();
                                                ArrayListElemsAll = new ArrayList<Element>(); 
                                                UpdateNodesValues(strategyRG, symmetricVariables, elParams5, breakdownLevelMax, 0);
                                                AddToList(strategyRG, symmetricVariables, elParams5, breakdownLevelMax, 0);
                                                if (!StrategyName2.equals(strName) && OutPutBlockMode) 
                                                {
                                                    StrategyName2 = strName;
                                                    strategyBase = getStrategyBase(strategyRG, symmetricVariables);
                                                    Strategie1 = strategyBase.getStrategyXml(); 

                                                    OutputPath = "C:\\Temp\\"+strName+"B.txt";
                                                    FileWriter myWriter = new FileWriter(OutputPath , false); 
                                                    String String1 = XMLUtil.elementToString(Strategie1);
                                                    myWriter.write(String1+"\r\n");
                                                    myWriter.close();
                                                }

                                                StringBuilder sb = new StringBuilder();																										// create the Building Blocks Name String
                                                if (ArrayListElemsAll.size()>=1)
                                                { 
                                                    if (DebugMode){
                                                    myWriter = new FileWriter(OutputPath , true); 
                                                    myWriter.write("ArrayListElemsAll.size() : "+ String.valueOf(ArrayListElemsAll.size())  + "\r\n");
                                                    String String1 = XMLUtil.elementToString(elParam5Temp);
                                                    myWriter.write(String1);
                                                    myWriter.close();}
                                                    for (int i5 = 0; i5 < ArrayListElemsAll.size(); i5++) 
                                                    {
                                                        elParam6Temp = ArrayListElemsAll.get(i5);

                                                        if (elParam6Temp != null) {
                                                            String elParamKey8Temp = elParam6Temp.getAttributeValue("name");                                                                //      elParam6Temp.getAttributeValue("key"); 
                                                            sb.append(elParamKey8Temp);
                                                            sb.append(ParamDelimiter);
                                                        }
                                                    }
                                                }
                                                return sb.toString();
                                            }}
                                        }}
                                    }
                                }}
                            }
                        }}
                    }
                }
                //#endregion
            }

            return "";
        } catch (Exception e) {
            if (DebugMode2){
            String strName = strategyRG.getName();
            OutputPath = "C:\\Temp\\toBuildingBlocksName "+strName+".txt";
            FileWriter myWriter = new FileWriter(OutputPath , true);  
            myWriter.write("Error : "+ strName +"     "+ "\r\n");
            myWriter.write("Error : "+  e + "\r\n");
            StrategyBase strategyBase = getStrategyBase(strategyRG, symmetricVariables);
            Element Strategie1 = strategyBase.getStrategyXml(); 
            String String1 = XMLUtil.elementToString(Strategie1);
            myWriter.write(String1 + "\r\n");
            myWriter.close();}
            Log.error("Error toBuildingBlocksName", e);
            return "";
        }
    }

 

9/ To read each Building Blocks, this example is using two recursive functions : UpdateNodesValues and AddToList.

These functions are searching for each Building Blocks whatever is the XML structure of the strategy.

Here is the Code :

   /**
    * Recursive function that read the Building Blocks Name from the Xml to update Nodes Values
    * @param strategyRG
    * @param symmetricVariables
    * @param Element
    * @param breakdownLevelMax
	 * @param breakdownLevel
    * @return
    */
   public void UpdateNodesValues(ResultsGroup strategyRG,  boolean symmetricVariables, Element element, int breakdownLevelMax, int breakdownLevel) throws Exception 
   {
       int i;
       if (element != null)
       {
           breakdownLevel = breakdownLevel + 1 ;
           List<Element> element1 = element.getChildren();
           if (element1.size() >= 1)
           {
               for (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");
           if (listParams.size() >= 1)
           {
               boolean VariableFounded = false;
               for (i = 0; i < listParams.size(); i++) 
               {
                   Element courant = listParams.get(i);
                   if (courant != null) 
                   {
                       String elParamKey5 = courant.getAttributeValue("key");					    			// the name
                       String elParamVariable3 = courant.getAttributeValue("variable");					    // the variable
                       if (elParamKey5.startsWith("#") && elParamVariable3=="true")
                       {
                           String Temp1 =  VariableValues.get(courant.getText());
                           String Temp2 =  courant.getText();
                           if (Temp1 != null)
                           {
                               courant.setText(Temp1);
                           }
                           VariableFounded = true;
                       }
                   }
               }
           }
       }
   }

   /**
    * Recursive function that read the Building Blocks Name from the Xml to the ArrayList : ArrayListElemsAll
    * @param strategyRG
    * @param symmetricVariables
    * @param Element
    * @param breakdownLevelMax
	 * @param breakdownLevel
    * @return
    */
   public void AddToList(ResultsGroup strategyRG,  boolean symmetricVariables, Element element, int breakdownLevelMax, int breakdownLevel) throws Exception 
   {
       int i;
       boolean Condition1 = false;
       if (element != null)
       {
           breakdownLevel = breakdownLevel + 1 ;

           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();
               if (element1.size() >= 1)
               {
                   for (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); 
                               }
                           }
                   }

                   if (breakdownLevel <= breakdownLevelMax && OutPutBlockMode)
                   {
                       String strName = strategyRG.getName();
                       OutputPath = "C:\\Temp\\"+strName+".txt";
                       FileWriter myWriter = new FileWriter(OutputPath , true); 
                       String String1 = XMLUtil.elementToString(elementCopy);
                       myWriter.write(String1+"\r\n");
                       myWriter.write("________________________________________________________________________________________________________________________________________________________________________________________________________________"+"\r\n");
                       myWriter.close();
                   }

           }
       }
   }

10/ Conclusion

In Summary, it is simple, we usually start by reading the structure of the XML file from the XMLUtil.elementToString function, then we are using the above functions (A,B,C,D,E)

We can find more functions if necessary at :

https://strategyquant.com/sqxapi/com/strategyquant/lib/XMLUtil.html

 

Source of information :

https://strategyquant.com/doc/programming-for-sq/viewing-and-changing-strategy-parameters-version-2/

https://www.w3schools.com/xml/default.asp

https://strategyquant.com/sqxapi/com/strategyquant/lib/XMLUtil.html

https://www.tutorialspoint.com/java_xml/java_jdom_parse_document.htm

 

A useful Xml reader :

https://jsonformatter.org/xml-editor

 

My name is Emmanuel Bouillant-Evrard, Engineer specialized in Finance. I worked in Research and Development in Finance in USA, Canada and France for 24 years.

 

Subscribe
Notify of
4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
clonex / Ivan Hudec
7. 6. 2022 5:21 pm

excellent

innggo
8. 7. 2023 12:31 pm

Thanks Emmanuel !

Jordan
13. 11. 2023 7:24 am

Great job done