Documentação e Guias do Usuário
Aprenda o básico, ou aperfeiçoe suas habilidades com tutoriais projetados para inspirar.
Última atualização em 21. 6. 2022 por Mark Fric
Filtrar por correlação - exemplo de plugin
Conteúdo da página
Nota
- Esse exemplo e a funcionalidade que ele requer são adicionados somente ao SQ Build 136 Dev 2 ou posterior
- A funcionalidade descrita é apenas para usuários "avançados" e dedicados. Ela não está completamente documentada; este é o primeiro exemplo que mostra essa possibilidade.
Observação: há uma versão atualizada para o SQX Build 140 e superior. If you have some issues with appearing plugin in the user interface, please delete the cache in this folder SQ X install folderinternalelectronresourcesuserData and restart SQ X.
Instruções de instalação:
- Descompacte o arquivo na pasta de instalação do SQ X/user/extend/plugins
- Reiniciar SQ X
Este é um exemplo de como estender a funcionalidade do SQX com seu próprio plug-in.
O StrategyQuant X foi criado como um sistema baseado em plugins, cada parte do programa é um plugin. No entanto, estender o SQX com seu próprio plug-in não era possível até agora (Build 136 Dev 2), porque você precisava ter acesso ao código-fonte completo e não tinha como compilar seu plug-in.
A interface do usuário do SQX é basicamente um aplicativo da Web escrito em AngularJS, em que o backend está em servlets Java.
Neste exemplo, mostraremos passo a passo como criar um plug-in simples, incluindo uma interface de usuário simples.
O plug-in completo também está disponível como um arquivo ZIP anexado a este artigo.
Esse plug-in implementará uma funcionalidade de filtragem de estratégias por correlação. Ele funciona da seguinte forma:
- plugin, ele adicionará um novo botão Filtrar por correlação para o banco de dados
- Ao clicar no botão, uma caixa de diálogo pop-up é exibida, na qual o usuário configura a correlação máxima permitida
- Quando confirmado, o plug-in chamará seu método de backend e examinará todas as estratégias no banco de dados real, filtrando (removendo) as que tiverem correlação maior que a máxima com outras estratégias nesse banco de dados
Créditos - este plug-in é baseado no código postado por AgentePot no Discord como parte de nosso sessões de codificação ao vivoO código é usado com seu consentimento.
Localização dos plug-ins do usuário
Os plug-ins desenvolvidos pelo usuário devem estar localizados na pasta {Instalação do SQ}/user/extend/Plugins. Você pode fazer o download do arquivo ZIP desse plug-in e extraí-lo para essa pasta.
Ao abrir o CodeEditor, você deverá ver a pasta desse plug-in:
Esse plug-in consiste em três arquivos:
- FilterByCorrelationServlet.java - arquivo java que implementa a funcionalidade de filtragem de estratégias por correlação.
- module.js - Arquivo JavaScript que contém a definição do módulo no Angular
- popup.html - Arquivo HTML que contém a interface do usuário desse novo plug-in
Vamos examiná-los um a um, começando pelo mais simples.
Definição da interface do usuário para o plug-in - popup.html
A interface do usuário do plug-in é definida no arquivo popup.html. É um arquivo HTML padrão que é exibido em uma janela modal.
Há DIVs para decorar a janela, mas o "formulário" real é definido dentro do DIV modal-body:
<!-- Modal window-->
<div class="modal centered" id="filterByCorrelationButtonModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="myModalLabel" tsq>Filtrar por correlação</h4>
</div>
<div class="modal-body" style="height: auto;">
Funcionalidade - todas as estratégias que tiverem correlação maior que Max serão removidas do banco de dados atual.
<label tsq>Configurações de filtragem</label>
<div class="row">
<div class="col-sm-12">
<div class="col-sm-6">
<label class="sqn-label" tsq>Período de correlação:</label>
</div>
<div class="col-sm-6">
<select id="fbc-correlation-period" class="setting-control">
<option value="5" tsq>Hora</option>
<option value="10" selected tsq>Dia</option>
<option value="20" tsq>Semana</option>
<option value="30" tsq>Mês</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="col-sm-6">
<label class="sqn-label" tsq>Correlação máxima:</label>
</div>
<div class="col-sm-6">
<div class="sqn-spinner setting-control">
<input type="text" class="sqn-input" id="fbc-max-correlation" min="0" max="1" step="0.01" value="0.5" />
<div class="sqn-spinner-btns">
<div class="sqn-spinner-minus" onclick="sqnSpinnerMinus(this)"></div>
<div class="sqn-spinner-plus" onclick="sqnSpinnerPlus(this)"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<a data-dismiss="modal" tsq>Fechar</a>
<button type="button" class="btn btn-primary" onclick="onFilter()" tsq>Filtro</button>
</div>
</div>
</div>
</div>
<style>
#filterByCorrelationButtonModal .setting-control {
width: 100px;
}
</style>
<script>
function onFilter(){
let period = document.getElementById("fbc-correlation-period").value;
let maxCorrelation = document.getElementById("fbc-max-correlation").value;
const urlParams = new URLSearchParams({
projectName: window.parent.filterByCorrelationData.projectName,
databankName: window.parent.filterByCorrelationData.databankName,
period,
maxCorrelation
});
CustomPluginController.sendRequest("filterByCorrelation/filter?" + urlParams.toString(), "GET", null, function(response){
let responseJSON = JSON.parse(response);
console.error(responseJSON);
if(responseJSON.error){
alert(responseJSON.error);
}
else {
alert(responseJSON.success);
window.parent.hidePopup("#filterByCorrelationButtonModal");
}
});
}
</script>
O importante aqui é o id filterByCorrelationButtonModal que é usado na primeira linha. Isso é importante porque esse pop-up é referenciado por esse ID na função JavaScript em module.js.
Quando estiver desenvolvendo seu próprio plug-in, você deverá criar seu próprio ID exclusivo do pop-up e usar esse ID em module.js - ver mais tarde.
Outra especialidade é que usamos onClick() evento JavaScript para capturar o envio do formulário e, em seguida, usaremos JS simples para recuperar os valores configurados.
Em seguida, eles são enviados para o backend usando um método especial CustomPluginController.sendRequest() que faz uma solicitação para /filterByCorrelation/filtro em que ele passa os parâmetros do formulário e seu valor de retorno é exibido em um alerta.
Definição do plug-in em module.js
O plug-in precisa de um module.js para que ele seja devidamente reconhecido e incorporado à interface do usuário.
É um código Angular em JavaScript, mas você não precisa ter conhecimento detalhado do Angular. Você pode usar esse plug-in de exemplo e simplesmente copiar e colar + modificá-lo se estiver implementando seu próprio plug-in.
O código completo do module.js é:
angular.module('app.resultsdatabankactions.filterByCorrelation', ['sqplugin']).config(function(sqPluginProvider, $controllerProvider) {
function callback(projectName, taskName, databankName, selectedStrategies){
window.parent.filterByCorrelationData = {
projectName,
taskName,
databankName
};
window.parent.showPopup("#filterByCorrelationButtonModal");
}
let buttonController = new CustomPluginController('app.resultsdatabankactions.filterByCorrelation', $controllerProvider, callback).init();
sqPluginProvider.plugin("ResultsDatabankAction", 100, {
title: Ltsq("Tools:Filter by correlation"),
class: 'btn btn-normal btn-default',
controlador: buttonController,
id: "databank-action-filterbycorrelation"
});
sqPluginProvider.addPopupWindow("plugins/FilterByCorrelation/popup.html", null, 'SQUANT');
});
Vamos analisar o código parte por parte.
A primeira parte é registrar nosso novo plug-in como módulo Angular:
angular.module('app.resultsdatabankactions.filterByCorrelation', ['sqplugin']).config(function(sqPluginProvider, $controllerProvider) {
Geralmente, você só precisa dar a ele um nome exclusivo, como app.resultsdatabankactions.filterByCorrelation.
Internamente, usamos a convenção app.resultsdatabankaction.YourUniqueName
A segunda parte é criar um controlador de botão e um retorno de chamada que exibirá a caixa de diálogo pop-up.
função callback(projectName, taskName, databankName, selectedStrategies){
window.parent.filterByCorrelationData = {
projectName,
taskName,
databankName
};
window.parent.showPopup("#filterByCorrelationButtonModal");
}
let buttonController = new CustomPluginController('app.resultsdatabankactions.filterByCorrelation', $controllerProvider, callback).init();
O importante aqui é chamar o método window.parent.showPopup() ao qual você fornece um ID exclusivo do pop-up que foi definido anteriormente em popup.html. Como o nome sugere, chamar isso mostrará o popup e o nosso formulário,
e o controlador do botão o invoca quando o botão é clicado.
A terceira parte é registrar esse plug-in e definir onde ele será exibido:
sqPluginProvider.plugin("ResultsDatabankAction", 100, {
title: Ltsq("Filtrar por correlação"),
class: 'btn btn-normal btn-default',
controlador: buttonController,
id: "databank-action-filterbycorrelation"
});
Aqui dizemos que ele está conectado a ResultsDatabankAction ponto de extensão, o que significa que ele será exibido como um botão no banco de dados.
O que é interessante aqui é o título - se você não quiser que ele seja exibido como um botão separado, mas como outro item no Ferramentas você pode simplesmente usar o título:
título: Ltsq("Tools:Filter by correlation"),
Você também pode ver que definimos o controlador de botão e o configuramos para o nosso buttonController definido anteriormente.
A última parte é o registro do nosso arquivo de interface do usuário no sistema SQX pugin - isso garantirá que o arquivo pooup.html seja carregado e se torne parte da interface do usuário.
sqPluginProvider.addPopupWindow("plugins/FilterByCorrelation/popup.html", null, 'SQUANT');
Implementação do backend - FilterByCorrelationServlet.java
Agora que temos a interface do usuário, precisamos implementar a funcionalidade desejada no backend.
O backend é feito como um servlet HTTP que processa solicitações HTTP do frontend (UI) e executa a funcionalidade necessária. Se você se lembrar, definimos essa solicitação no arquivo popup.html, que usa um método especial CustomPluginController.sendRequest() que faz uma solicitação para /filterByCorrelation/filtro.
Portanto, temos que implementar um servlet que lide com essa solicitação e faça o que desejamos.
O servlet deve implementar IServletPlugin interface. O método importante aqui é getHandler()que é chamado quando o backend recebe uma solicitação para /filterByCorrelation/.
A solicitação é então tratada por nosso FilterByCorrelation classe interna que implementa a funcionalidade.
Portanto, a parte do snippet que apenas trata a solicitação e atribui um manipulador a ela é:
@PluginImplementation
public class FilterByCorrelationServlet implements IServletPlugin {
private static final Logger Log = LoggerFactory.getLogger(FilterByCorrelationServlet.class);
private ServletContextHandler connectionContext;
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
@Override
public String getProduct() {
return SQConst.CODE_SQ;
}
//------------------------------------------------------------------------
@Override
public int getPreferredPosition() {
return 0;
}
//------------------------------------------------------------------------
@Override
public void initPlugin() throws Exception {
}
//------------------------------------------------------------------------
@Override
public Handler getHandler() {
se (connectionContext == null){
connectionContext = new ServletContextHandler(ServletContextHandler.SESSIONS);
connectionContext.setContextPath("/filterByCorrelation/");
connectionContext.addServlet(new ServletHolder(new FilterByCorrelation()),"/*");
}
return connectionContext;
}
Classe interna FilterByCorrelation
Esta é a classe que trata a solicitação /filterByCorrelation/filtro da interface do usuário.
A primeira parte dessa classe verifica qual comando exatamente foi chamado - em nosso caso, há apenas filtro comando.
class FilterByCorrelation extends HttpJSONServlet {
@Override
protected String execute(String command, Map args, String method){
switch(command) {
case "filter": return onFilter(args);
default:
return apiErrorJSON("Falha na execução. comando desconhecido '"+command+"'.", null);
}
}
//------------------------------------------------------------------------
private String onFilter(Map args) {
JSONObject response = new JSONObject();
try {
String projectName = tryGetParam(args, "projectName")[0];
String databankName = tryGetParam(args, "databankName")[0];
int period = Integer.parseInt(tryGetParam(args, "period")[0]);
double maxCorrelation = Double.parseDouble(tryGetParam(args, "maxCorrelation")[0]);
int removedCount = filterByCorrelation(projectName, databankName, period, maxCorrelation);
response.put("success", "Strategies filtered, "+removedCount+" strategies removed.");
return response.toString();
}
catch(Exception e){
Log.error("Error while filtering strategies by correlation", e);
response.put("error", "Filtering failed - " + e.getMessage());
return response.toString();
}
}
Ao receber esse comando, ele executará onFilter() método que:
- obtém parâmetros como nome do projeto, nome do banco de dados, período e maxCorrelation dos parâmetros da solicitação
- realiza a filtragem real por correlação chamando o método filterByCorrelation(projectName, databankName, period, maxCorrelation)
- ele enviará de volta uma mensagem com o número real de estratégias removidas ou uma mensagem de erro em caso de erro.
método filterByCorrelation()
esse método executa a filtragem real, analisando todas as estratégias no banco de dados real, calculando as correlações entre as estratégias e removendo as estratégias em que a correlação é maior que maxCorrelation.
A correlação de computação merece um artigo e um exemplo por si só, mas você pode acompanhar como ela é implementada no código:
private int filterByCorrelation(String projectName, String databankName, int period, double maxCorrelation) throws Exception {
Log.info("Filtragem por correlação (Project: " + projectName + ", banco de dados: " + databankName + ")...");
SQProject project = ProjectEngine.get(projectName);
Banco de dados databank = project.getDatabanks().get(databankName);
int removedCount = 0;
// Verificação de estratégias correlacionadas usando a pontuação de adequação como uma lista de classificação/prioridade
ArrayList rgSortedCandidates = new ArrayList(databank.getRecords());
rgSortedCandidates.sort((o1, o2) -> Double.valueOf(o1.getFitness()).compareTo(Double.valueOf(o2.getFitness())));
ArrayList rgSortedCandidatesRanked = new ArrayList();
for(ResultsGroup rgSC : rgSortedCandidates) {
rgSortedCandidatesRanked.add(0, rgSC);
}
ArrayList rgUncorrelated = new ArrayList();
// Isso deve ser resolvido usando uma classificação adicional (ou seja, fitness > pf > ret/dd ... etc.)
enquanto (rgSortedCandidatesRanked.size() > 0) {
ResultsGroup focusStrat = rgSortedCandidatesRanked.get(0).clone();
String focusStratName = focusStrat.getName();
Log.info("Estratégia de foco para comparar: {}", focusStratName);
rgUncorrelated.add(focusStrat.clone()); // adiciona a melhor estratégia do conjunto à lista não correlacionada como ponto de partida
rgSortedCandidatesRanked.remove(0);
Iterator it = rgSortedCandidatesRanked.iterator();
while(it.hasNext()) {
ResultsGroup subStrat = it.next();
String subStratName = subStrat.getName();
se (subStratName != focusStratName) {
CorrelationPeriods corrPeriods = new CorrelationPeriods();
CorrelationType corrType = CorrelationTypes.getInstance().findClassByName("ProfitLoss");
CorrelationComputer correlationComputer = new CorrelationComputer();
// computar períodos de correlação
CorrelationPeriods correlationPeriods = precomputePeriodsAP(focusStrat, subStrat, period, corrType);
double corrValue = SQUtils.round2(correlationComputer.computeCorrelation(false, focusStratName, subStratName, focusStrat.orders(), subStrat.orders(), correlationPeriods, corrType));
Log.info(" - Correlação de '{}'' com a estratégia de foco: {}", subStratName, corrValue);
se (corrValue > maxCorrelation) {
it.remove();
removedCount++;
Log.info(" - Removendo a estratégia " + subStratName + " (correlação " + corrValue + " > " + maxCorrelation + ")...");
banco de dados.remove(subStratName, true, true, true, true, true, true, null);
}
} else {
it.remove();
}
}
}
return removedCount;
}
//------------------------------------------------------------------------
private CorrelationPeriods precomputePeriodsAP(ResultsGroup paramResultsGroup1, ResultsGroup paramResultsGroup2, int paramInt, CorrelationType paramCorrelationType) throws Exception {
CorrelationPeriods correlationPeriods = new CorrelationPeriods();
TimePeriod timePeriod = CorrelationLib.getPeriod(paramResultsGroup1.orders());
long l1 = timePeriod.from;
long l2 = timePeriod.to;
timePeriod = CorrelationLib.getPeriod(paramResultsGroup2.orders());
se (timePeriod.from l2) {
l2 = timePeriod.to;
}
TimePeriods timePeriods1 = CorrelationLib.generatePeriods(paramInt, l1, l2);
TimePeriods timePeriods2 = timePeriods1.clone();
paramCorrelationType.computePeriods(paramResultsGroup1.orders(), paramInt, timePeriods1);
correlationPeriods.put(paramResultsGroup1.getName(), timePeriods1);
paramCorrelationType.computePeriods(paramResultsGroup2.orders(), paramInt, timePeriods2);
correlationPeriods.put(paramResultsGroup2.getName(), timePeriods2);
return correlationPeriods;
}
}
Trabalhar com plug-ins no Code Editor
Adicionamos uma nova funcionalidade para trabalhar com plug-ins definidos pelo usuário no SQX Build 136 Dev 2.
Se você descompactou o plug-in anexado na pasta correta ({SQ installation}/user/extend/Plugins) e abra o Code Editor, você verá uma nova seção Plugins com nosso novo plug-in:
Normalmente, você pode criar e editar arquivos e pastas lá, como de costume. O novo recurso é a possibilidade de compilar o plug-in.
Clique com o botão direito do mouse na pasta do plug-in e selecione Compilar plug-in:
O plug-in será compilado e um novo arquivo FilterByCorrelation.jar aparecerá na pasta.
Agora reinicie o StrategyQuant e você verá um novo botão de banco de dados:
Quando você clicar nele, deverá abrir a caixa de diálogo mostrada abaixo:
Defina as configurações de filtragem e clique no botão Filter (Filtrar). Se você tiver algumas estratégias no banco de dados, poderá notar que algumas delas serão removidas e um alerta será exibido:
Portanto, nosso plug-in funcionou: ele calculou e comparou as correlações entre todas as estratégias no banco de dados atual e removeu cinco estratégias que tinham correlação maior do que a correlação máxima configurada.
Este artigo foi útil? O artigo foi útil O artigo não foi útil
Conteúdo da página





