Documentation

Applications

Dernière mise à jour le 11. 1. 2023 par Mark Fric

Sélection programmatique de blocs de construction

Il s'agit d'une extension de cet article : https://strategyquant.com/doc/programming-for-sq/changing-task-config-programmatically/
qui a démontré comment vous pouvez modifier la configuration des tâches de manière programmatique.

L'idée générale de l'exemple initial est que vous pouvez modifier la configuration d'une tâche en manipulant sa configuration XML et en la réappliquant à la tâche.
Dans cet exemple, nous allons montrer comment vous pouvez activer/désactiver les blocs de construction de cette manière.

 

Comment les blocs de construction sont stockés dans le XML de la tâche

Tous les blocs de construction sont stockés en tant qu'enfants et sous-enfants dans l'élément ->.

Chaque bloc de construction est configuré dans son propre élément , identifié de manière unique par son élément clé - qui est le nom de son extrait.

 

Il existe quelques normes en matière de valeurs clés :

  • s'il est bloc de signaux ou comparaisonla clé ne contient que le nom de l'extrait, par exemple key="ADXChangesDown" ou key="IsGreater"
  • s'il est indicateur (pas de signal), sa clé est précédée de la chaîne "Indicateur", par exemple key="Indicators.ADX"
  • s'il est prixsa clé est préfixée par la chaîne "Prix", par exemple key="Prix.Haut"
  • s'il est niveau d'arrêt/limite (pour les ordres Stop ou Limite), sa clé est préfixée par la chaîne "Niveaux de prix Stop/Limite", par exemple key="Niveaux de prix stop/limite.TEMA"
  • s'il est plage d'arrêt/limite (pour les ordres Stop ou Limite), sa clé est préfixée par la chaîne "Plages de prix Stop/Limite", par exemple key="Fourchette de prix Stop/Limite.BBWidthRatio"

 

Un autre attribut important de l'élément est utiliser. Si vous voulez que le bloc soit utilisé pendant la construction, vous devez le mettre à "true", sinon à "false".

Ainsi, si vous souhaitez activer ou désactiver un bloc particulier, il vous suffit de le faire :

  1. trouver l'élément de ce dernier
  2. définir l'attribut use à true ou false comme ceci : ...

 

Un exemple de XML de tâche de construction est joint à cet article - fichier Build-Task1.xml

 

Exemple

Pour illustrer cette fonctionnalité, nous allons basculer de manière programmatique entre les blocs de signaux Keltner Channel (KC) et Bollinger Bands (BB), tous les autres blocs étant désactivés.

Nous aurons un projet personnalisé avec deux tâches - la première sera la tâche d'analyse personnalisée qui appliquera notre snippet d'analyse personnalisée. La seconde est la tâche Builder - nous allons modifier la configuration de cette tâche Builder dans notre snipet CA.

 

Ainsi, lorsque vous exécutez le projet personnalisé pour la première fois, seuls les blocs de signaux de bandes de Bollinger sont activés. Lors de la deuxième exécution, seuls les blocs du canal de Keltner sont activés, et ainsi de suite.

Tous les blocs de signaux des bandes de Bollinger ont des extraits nommés avec le préfixe BB - BB*********, par exemple clé="BBBarClosesAboveDown", et tous les blocs de signaux du canal de Keltner ont des extraits nommés KC*********, par exemple clé="KCBarClosesAboveLower".
Nous utiliserons le préfixe BB ou KC pour reconnaître qu'il s'agit d'un bloc de signaux du canal de Keltner ou des bandes de Bollinger.

L'exemple ci-dessous est essentiellement le même que celui de l'article https://strategyquant.com/doc/programming-for-sq/changing-task-config-programmatically/ - Seulement ici, nous faisons des choses différentes avec le XML.

Nous utilisons la norme JDOM pour parcourir le XML et obtenir ou modifier ses attributs.

Étape 1 - Obtenir tous les éléments du bloc

Element elBlocks = XMLUtil.getChildElem(elNewConfig, "Blocks") ;
if(elBlocks == null) {
    throw new Exception("No  element exists, is it Builder task ?") ;
}
Element buildingBlocks = XMLUtil.getChildElem(elBlocks, "BuildingBlocks") ;
// vous pouvez également charger la configuration de la nouvelle tâche à partir d'un fichier préparé
//Elément elNewConfig = XMLUtil.fileToXmlElement(new File("c:/BuildTask2009_2019.xml")) ;

List blocks = buildingBlocks.getChildren("Block") ;

 

Étape 2 - Initialisation de la variable activeBlock

nous utiliserons cette variable pour déterminer si les blocs BB ou KC doivent être utilisés - n'oubliez pas que nous passons d'un bloc BB à un bloc KC, et que nous devons donc déterminer lequel de ces deux blocs doit être activé ou désactivé.

// nous utiliserons cette variable pour passer de BB à KC. Les valeurs sont les suivantes
// 0 - inconnu, sera défini par le premier bloc trouvé
// 1 - Les blocs BB doivent être actifs
// 2 - Les blocs KC doivent être actifs
int activeBlock = 0 ;

 

Étape 3 - Passer en revue tous les blocs en boucle

for(int i=0 ; i<blocks.size() ; i++) {
    Element elBlock = blocks.get(i) ;

    String key = elBlock.getAttributeValue("key") ;

 

Étape 4 - Si la clé ne commence pas par BB ou KC, il s'agit d'un bloc différent qui doit être désactivé.

if(!key.startsWith("BB") && !key.startsWith("KC")) {
    // il ne s'agit pas d'un bloc de bandes de Bollinger ou de canal de Keltner, désactivez-le
    elBlock.setAttribute("use", "false") ;
    continuer ;
}

 

Étape 5 - Sinon, il s'agit d'un bloc KC ou BB

Reconnaissez maintenant la valeur correcte de la variable activeBlock :

// il s'agit d'un bloc BB ou KC
String use = elBlock.getAttributeValue("use") ;

if(activeBlock == 0) {
    // nous déterminerons si les blocs BB ou KC doivent être actifs en fonction du premier bloc trouvé
    if(key.startsWith("BB")) {
        if (use.equals("true")) {
            // le bloc BB était actif avant, maintenant c'est le bloc KC qui sera actif
            activeBlock = 2 ;
        }
    } else if(key.startsWith("KC")) {
        if(use.equals("true")) {
            // KC était actif avant, maintenant BB sera actif
            activeBlock = 1 ;
        }
    }

    if(activeBlock == 0) {
        activeBlock = 1 ;
    }

    Log.info("----- Tournant sur "+(activeBlock == 1 ? "Bollinger Bands" : "Keltner Channel")+" blocs.") ;
}

 

Étape 6 - l'essentiel

tourner les blocs BB ou KC sur ON en fonction de l'état d'avancement du projet. bloc actif en fixant leur attribut use à true ou false :

// maintenant, activer ou désactiver le bloc en fonction de la valeur de activeBlock
if(key.startsWith("BB"))) {
    elBlock.setAttribute("use", (activeBlock == 1 ? "true" : "false")) ;
} else if(key.startsWith("KC")) {
    elBlock.setAttribute("use", (activeBlock == 2 ? "true" : "false")) ;
}

 

Étape 7 - Appliquer la configuration modifiée à la tâche

Nous avons fini de passer en revue tous les blocs de construction, il ne reste plus qu'à appliquer la configuration modifiée à la tâche :

// Appliquer la configuration modifiée à la tâche
buildTask.setConfig(elNewConfig, true) ;

// ceci notifie l'interface utilisateur de charger la configuration modifiée et de l'appliquer à l'interface utilisateur.
// Sans cela, cela fonctionnerait toujours mais vous ne verriez pas les changements dans l'interface utilisateur.
JSONObject jsonData = new JSONObject().put("projectConfig", sqProject.toJSON()) ;
DataToSend dataToSend = new DataToSend(WebSocketConst.UpdateProject, jsonData) ;
SQWebSocketManager.addToDataQueue(dataToSend, SQConst.CODE_TASKMANAGER) ;

 

Et c'est tout.

Désormais, chaque fois que vous démarrerez le projet personnalisé, les blocs de construction alterneront entre les signaux des bandes de Bollinger et ceux du canal de Keltner.

 

 

Code complet de l'extrait CAChangeBlocksConfig :

package SQ.CustomAnalysis ;

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.json.JSONObject ;

import java.util.ArrayList ;
import java.util.List ;

public class CAChangeBlocksConfig extends CustomAnalysisMethod {

    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    //------------------------------------------------------------------------

    public CAChangeBlocksConfig() {
        super("CAChangeBlocksConfig", TYPE_PROCESS_DATABANK) ;
    }

    //------------------------------------------------------------------------

    @Override
    public ArrayList processDatabank(String project, String task, String databankName, ArrayList databankRG) throws Exception {

        // récupération du projet en cours
        SQProject sqProject = ProjectEngine.get(project) ;

        // Obtention d'une tâche par son nom
        ISQTask buildTask = sqProject.getTaskByName("Build strategies") ;
        if(buildTask == null) {
            throw new Exception("No such task exists !") ;
        }
        // vous pouvez également utiliser sqProject.getTasks() pour obtenir une liste de toutes les tâches
        // et les parcourir pour obtenir celle que vous voulez


        // voici comment obtenir les paramètres XML des tâches de la nouvelle manière (SQ 136 up)
        // Il renvoie un élément XML JDOM avec la configuration complète de la tâche
        Element elConfig = buildTask.getConfig() ;
        // créer une nouvelle configuration en la clonant - il est important de faire un clone,
        // sinon votre nouvelle configuration ne sera pas appliquée
        Elément elNewConfig = elConfig.clone() ;

        // modifiez maintenant tout ce qui se trouve dans la nouvelle configuration
        Element elBlocks = XMLUtil.getChildElem(elNewConfig, "Blocks") ;
        if(elBlocks == null) {
            throw new Exception("No  element exists, is it Builder task ?") ;
        }
        Element buildingBlocks = XMLUtil.getChildElem(elBlocks, "BuildingBlocks") ;
        // alternativement, vous pouvez charger la configuration de la nouvelle tâche à partir d'un fichier préparé
        //Elément elNewConfig = XMLUtil.fileToXmlElement(new File("c:/BuildTask2009_2019.xml")) ;

        List blocks = buildingBlocks.getChildren("Block") ;

        // nous utiliserons cette variable pour passer de BB à KC. Les valeurs sont les suivantes
        // 0 - inconnue, sera définie par le premier bloc trouvé
        // 1 - Les blocs BB doivent être actifs
        // 2 - Les blocs KC doivent être actifs
        int activeBlock = 0 ;

        for(int i=0 ; i<blocks.size() ; i++) {
            Element elBlock = blocks.get(i) ;

            String key = elBlock.getAttributeValue("key") ;

            if(!key.startsWith("BB") && !key.startsWith("KC")) {
                // il ne s'agit pas d'un bloc de bandes de Bollinger ou de canal de Keltner, désactivez-le
                elBlock.setAttribute("use", "false") ;
                continuer ;
            }

            // il s'agit d'un bloc BB ou KC
            String use = elBlock.getAttributeValue("use") ;

            if(activeBlock == 0) {
                // nous déterminerons si les blocs BB ou KC doivent être actifs en fonction du premier bloc trouvé
                if(key.startsWith("BB")) {
                    if (use.equals("true")) {
                        // le bloc BB était actif avant, maintenant c'est le bloc KC qui sera actif
                        activeBlock = 2 ;
                    }
                } else if(key.startsWith("KC")) {
                    if(use.equals("true")) {
                        // KC était actif avant, maintenant BB sera actif
                        activeBlock = 1 ;
                    }
                }

                if(activeBlock == 0) {
                    activeBlock = 1 ;
                }

                Log.info("----- Tourner sur "+(activeBlock == 1 ? "Bollinger Bands" : "Keltner Channel")+" blocs.") ;
            }

            // active ou désactive maintenant le bloc en fonction de la valeur de activeBlock
            if(key.startsWith("BB"))) {
                elBlock.setAttribute("use", (activeBlock == 1 ? "true" : "false")) ;
            } else if(key.startsWith("KC")) {
                elBlock.setAttribute("use", (activeBlock == 2 ? "true" : "false")) ;
            }
        }


        // Appliquer la configuration modifiée à la tâche
        buildTask.setConfig(elNewConfig, true) ;

        // ceci notifie l'interface utilisateur de charger la configuration modifiée et de l'appliquer à l'interface utilisateur.
        // Sans cela, cela fonctionnerait toujours mais vous ne verriez pas les changements dans l'interface utilisateur.
        JSONObject jsonData = new JSONObject().put("projectConfig", sqProject.toJSON()) ;
        DataToSend dataToSend = new DataToSend(WebSocketConst.UpdateProject, jsonData) ;
        SQWebSocketManager.addToDataQueue(dataToSend, SQConst.CODE_TASKMANAGER) ;

        return databankRG ;
    }
}

 

Cet article a-t-il été utile ? L'article était utile L'article n'était pas utile

S'abonner
Notification pour
1 Commentaire
Le plus ancien
Le plus récent Le plus populaire
Commentaires en ligne
Afficher tous les commentaires
Emmanuel
15. 1. 2023 7:24 pm

Merci Mark pour cet excellent exemple
Il sera très utile

Postes connexes