Documentazione

Applicazioni

Ultimo aggiornamento il 11. 1. 2023 da Mark Fric

Selezione programmatica dei blocchi di costruzione

Si tratta di un'estensione di questo articolo: https://strategyquant.com/doc/programming-for-sq/changing-task-config-programmatically/
che ha dimostrato come sia possibile modificare la configurazione dei task in modo programmatico.

L'idea generale dell'esempio iniziale è che si può cambiare la configurazione del task manipolando la sua configurazione XML e riapplicandola al task.
In questo esempio dimostreremo come sia possibile attivare/disattivare i blocchi di costruzione in questo modo.

 

Come vengono memorizzati i blocchi di costruzione nell'XML dell'attività

Tutti i blocchi di costruzione sono memorizzati come figli e sottofigli nell'elemento ->.

Ogni blocco di costruzione è configurato in un proprio elemento , identificato in modo univoco dal suo elemento chiave - che è il nome dello snippet.

 

Esistono alcuni standard nei valori chiave:

  • se è blocco del segnale o confronto, la chiave contiene solo il nome dello snippet, per esempio chiave="ADXChangesDown" o chiave="IsGreater"
  • se è indicatore (non segnale), la sua chiave è preceduta dalla stringa "Indicatore.", ad esempio key="Indicatori.ADX"
  • se è prezzo, la sua chiave è preceduta dalla stringa "Prezzi", ad esempio key="Prices.High"
  • se è livello di arresto/limite (per gli ordini Stop o Limit), la sua chiave è preceduta dalla stringa "Stop/Limit Price Levels.", ad esempio key="Livelli di prezzo stop/limite.TEMA"
  • se è intervallo di arresto/limite (per gli ordini Stop o Limit), la sua chiave è preceduta dalla stringa "Stop/Limit Price Ranges.", ad esempio key="Intervalli di prezzo stop/limite.BBWidthRatio"

 

Un altro importante attributo dell'elemento è utilizzo. Se si vuole che il blocco sia usato durante la compilazione, occorre impostarlo su "true", altrimenti su "false".

Quindi, se si desidera attivare o disattivare un blocco particolare, è sufficiente farlo:

  1. trovare il suo elemento <Block
  2. impostare l'attributo use su true o false in questo modo: ...

 

In questo articolo è allegato un esempio di XML dell'attività del costruttore: il file Build-Task1.xml.

 

Esempio

Come esempio di questa funzionalità, passeremo programmaticamente tra i blocchi di segnali Keltner Channel (KC) e Bollinger Bands (BB), mentre tutti gli altri blocchi saranno disabilitati.

Avremo un progetto personalizzato con due task: il primo sarà il task Analisi personalizzata che applicherà il nostro frammento di analisi personalizzata. Il secondo è il task Builder, di cui modificheremo la configurazione nel nostro snippet CA.

 

Pertanto, quando si esegue il progetto personalizzato per la prima volta, vengono abilitati solo i blocchi dei segnali delle Bande di Bollinger. Quando si esegue la seconda volta, vengono abilitati solo i blocchi del Canale di Keltner e così via.

Tutti i blocchi di segnali delle Bande di Bollinger hanno snippet denominati con il prefisso BB - BB*********, ad esempio key="BBBarClosesAboveDown", e tutti i blocchi di segnali del Canale Keltner hanno snippet denominati KC*********, ad esempio key="KCBarClosesAboveLower".
Utilizzeremo il prefisso BB o KC per riconoscere il blocco di segnali Keltner Channel o Bollinger Bands.

L'esempio riportato di seguito è essenzialmente lo stesso dell'articolo https://strategyquant.com/doc/programming-for-sq/changing-task-config-programmatically/ - solo che qui facciamo cose diverse con l'XML.

Utilizziamo lo standard JDOM per esaminare l'XML e ottenere o modificare i suoi attributi.

Passo 1 - Ottenere tutti gli elementi del blocco

Elemento elBlocks = XMLUtil.getChildElem(elNewConfig, "Blocks");
if(elBlocks == null) {
    throw new Exception("Non esiste alcun elemento , è un compito del costruttore?");
}
Element buildingBlocks = XMLUtil.getChildElem(elBlocks, "BuildingBlocks");
// In alternativa, si può caricare la configurazione del nuovo task da un file preparato
//Element elNewConfig = XMLUtil.fileToXmlElement(new File("c:/BuildTask2009_2019.xml"));

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

 

Passo 2 - Inizializzare la variabile activeBlock

useremo questa variabile per determinare se devono essere usati i blocchi BB o KC - ricordiamo che stiamo passando da un blocco BB a uno KC, quindi dobbiamo determinare quale dei due deve essere attivato e disattivato.

// useremo questa variabile per passare da BB a KC. I valori sono:
// 0 - non conosciuto, sarà impostato dal primo blocco trovato
// 1 - i blocchi BB devono essere attivi
// 2 - I blocchi KC devono essere attivi
int activeBlock = 0;

 

Fase 3 - Passare attraverso tutti i blocchi in un ciclo

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

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

 

Fase 4 - Se la chiave non inizia con BB o KC, si tratta di un blocco diverso e deve essere disattivato.

if(!key.startsWith("BB") && !key.startsWith("KC")) {
    // non è un blocco Bande di Bollinger o Canale di Keltner, disattivarlo
    elBlock.setAttribute("use", "false");
    continua;
}

 

Fase 5 - Altrimenti è un blocco KC o BB

Ora riconosciamo il valore corretto della variabile activeBlock:

// è un blocco BB o KC
String use = elBlock.getAttributeValue("use");

if(activeBlock == 0) {
    // determineremo se i blocchi BB o KC devono essere attivi in base al primo blocco trovato
    if(key.startsWith("BB")) {
        if (use.equals("true")) {
            // Prima era attivo BB, ora sarà attivo KC
            activeBlock = 2;
        }
    } else if(key.startsWith("KC")) {
        if(use.equals("true")) {
            // Prima era attivo KC, ora sarà attivo BB
            activeBlock = 1;
        }
    }

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

    Log.info("----- Girando su "+(activeBlock == 1 ? "Bollinger Bands" : "Keltner Channel")+" blocchi.");
}

 

Fase 6 - la cosa principale

Attivare i blocchi BB o KC in base alla blocco attivo impostando l'attributo use su true o false:

// ora attivare o disattivare il blocco in base al valore di activeBlock
if(key.startsWith("BB")) {
    elBlock.setAttribute("use", (activeBlock == 1 ? "true" : "false"));
} else if(key.startsWith("KC")) {
    elBlock.setAttribute("use", (activeBlock == 2 ? "true" : "false"));
}

 

Passo 7 - applicare la configurazione modificata all'attività

Abbiamo finito di esaminare tutti i blocchi di costruzione, ora basta applicare la configurazione modificata all'attività:

// Applicare la configurazione modificata al task
buildTask.setConfig(elNewConfig, true);

// questo notifica l'interfaccia utente per caricare la configurazione modificata e applicarla all'interfaccia utente.
// Senza questa operazione, funzionerebbe comunque, ma non si vedrebbero le modifiche nell'interfaccia utente.
JSONObject jsonData = new JSONObject().put("projectConfig", sqProject.toJSON());
DataToSend dataToSend = new DataToSend(WebSocketConst.UpdateProject, jsonData);
SQWebSocketManager.addToDataQueue(dataToSend, SQConst.CODE_TASKMANAGER);

 

E questo è tutto.

Ora, ogni volta che si avvia il progetto personalizzato, i blocchi di costruzione vengono commutati tra le Bande di Bollinger e i segnali del Canale di Keltner.

 

 

Codice completo dello snippet CAChangeBlocksConfig:

pacchetto SQ.CustomAnalysis;

importare com.strategyquant.lib.XMLUtil;
importare com.strategyquant.lib.constants.SQConst;
importare com.strategyquant.tradinglib.CustomAnalysisMethod;
importare com.strategyquant.tradinglib.ResultsGroup;
importare com.strategyquant.tradinglib.project.ProjectEngine;
importare com.strategyquant.tradinglib.project.SQProject;
importare com.strategyquant.tradinglib.project.websocket.DataToSend;
importare com.strategyquant.tradinglib.project.websocket.SQWebSocketManager;
importare com.strategyquant.tradinglib.project.websocket.WebSocketConst;
importare com.strategyquant.tradinglib.taskImpl.ISQTask;
importare org.jdom2.Element;
importare org.json.JSONObject;

importare java.util.ArrayList;
importare 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 {

        // ottenere il progetto corrente
        SQProject sqProject = ProjectEngine.get(project);

        // ottenere l'attività per nome
        ISQTask buildTask = sqProject.getTaskByName("Build strategies");
        if(buildTask == null) {
            lancia una nuova eccezione("Non esiste un task di questo tipo!");
        }
        // In alternativa, è possibile utilizzare sqProject.getTasks() per ottenere un elenco di tutti i task
        // e scorrerli per ottenere quello che si desidera


        // questo è il modo in cui si ottiene l'XML delle impostazioni delle attività nel nuovo modo (SQ 136 up)
        // Restituisce l'elemento XML JDOM con la configurazione completa dell'attività
        Element elConfig = buildTask.getConfig();
        // creare una nuova configurazione clonandola - è importante fare un clone,
        // altrimenti la nuova configurazione non verrà applicata
        Element elNewConfig = elConfig.clone();

        // ora modificare qualsiasi cosa nella nuova configurazione
        Element elBlocks = XMLUtil.getChildElem(elNewConfig, "Blocks");
        if(elBlocks == null) {
            throw new Exception("Non esiste alcun elemento , è un compito del costruttore?");
        }
        Element buildingBlocks = XMLUtil.getChildElem(elBlocks, "BuildingBlocks");
        // In alternativa, si può caricare la configurazione del nuovo task da un file preparato
        //Element elNewConfig = XMLUtil.fileToXmlElement(new File("c:/BuildTask2009_2019.xml"));

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

        // Useremo questa variabile per passare da BB a KC. I valori sono:
        // 0 - non conosciuto, sarà impostato dal primo blocco trovato
        // 1 - i blocchi BB devono essere attivi
        // 2 - I blocchi KC devono essere attivi
        int activeBlock = 0;

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

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

            if(!key.startsWith("BB") && !key.startsWith("KC")) {
                // non è un blocco Bande di Bollinger o Canale di Keltner, disattivarlo
                elBlock.setAttribute("use", "false");
                continua;
            }

            // è un blocco BB o KC
            String use = elBlock.getAttributeValue("use");

            if(activeBlock == 0) {
                // determineremo se i blocchi BB o KC devono essere attivi in base al primo blocco trovato
                if(key.startsWith("BB")) {
                    if (use.equals("true")) {
                        // Prima era attivo BB, ora sarà attivo KC
                        activeBlock = 2;
                    }
                } else if(key.startsWith("KC")) {
                    if(use.equals("true")) {
                        // Prima era attivo KC, ora sarà attivo BB
                        activeBlock = 1;
                    }
                }

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

                Log.info("----- Girando su "+(activeBlock == 1 ? "Bollinger Bands" : "Keltner Channel")+" blocchi.");
            }

            // ora attiva o disattiva il blocco in base al valore di activeBlock
            if(key.startsWith("BB")) {
                elBlock.setAttribute("use", (activeBlock == 1 ? "true" : "false"));
            } else if(key.startsWith("KC")) {
                elBlock.setAttribute("use", (activeBlock == 2 ? "true" : "false"));
            }
        }


        // Applicare la configurazione modificata al task
        buildTask.setConfig(elNewConfig, true);

        // questo notifica l'interfaccia utente per caricare la configurazione modificata e applicarla all'interfaccia utente.
        // Senza questa operazione funzionerebbe comunque, ma non si vedrebbero le modifiche nell'interfaccia utente.
        JSONObject jsonData = new JSONObject().put("projectConfig", sqProject.toJSON());
        DataToSend dataToSend = new DataToSend(WebSocketConst.UpdateProject, jsonData);
        SQWebSocketManager.addToDataQueue(dataToSend, SQConst.CODE_TASKMANAGER);

        restituire databankRG;
    }
}

 

Questo articolo è stato utile? L'articolo è stato utile L'articolo non è stato utile

Abbonarsi
Notificami
1 Commento
Il più vecchio
Più recente I più votati
Feedback in linea
Visualizza tutti i commenti
Emmanuel
15. 1. 2023 7:24 pm

Grazie Mark per questo eccellente esempio
Sarà molto utile

Messaggi correlati