Documentazione
Applicazioni
Ultimo aggiornamento il 11. 1. 2023 da Mark Fric
Selezione programmatica dei blocchi di costruzione
Contenuto della pagina
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:
- trovare il suo elemento <Block
- 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
Grazie Mark per questo eccellente esempio
Sarà molto utile