Documentazione

Applicazioni

Ultimo aggiornamento il 18. 5. 2020 da Mark Fric

Indicatore delle buste

in questo esempio aggiungeremo Buste a StrategyQuant X.

Il codice MQL per questo indicatore è disponibile qui: https://www.mql5.com/en/code/7975

Questo indicatore è già incorporato in MetaTrader e può essere richiamato dal codice MQL utilizzando il metodo iEnvelopes. Ecco come appare l'indicatore sul grafico:

I passi da seguire per aggiungere un nuovo indicatore a SQ X sono pochi:

  1. Aggiunta di un nuovo blocco di indicatori 
    creeremo un nuovo snippet di indicatore e aggiorneremo il suo codice per calcolare l'indicatore Envelopes.
  2. (Facoltativo, consigliato) Test del nuovo indicatore in SQ X rispetto ai dati di MT
    durante o dopo l'implementazione dovremmo confrontare i valori dell'indicatore calcolati da SQ con quelli calcolati da MQL - per assicurarci che l'indicatore sia implementato correttamente
  3. Aggiunta della traduzione del blocco Indicatore nella lingua della piattaforma di destinazione
    L'indicatore funziona ora in SQ, ma le strategie che lo utilizzano non lo fanno. Dobbiamo aggiungere modelli e generare codice sorgente per questo indicatore per ogni piattaforma di trading che vogliamo supportare.

 

Aggiunta di un nuovo snippet di indicatore

per farlo, apriremo Editor di codice.

Lì facciamo clic su Creare un nuovo nella barra degli strumenti

e nella finestra di dialogo a comparsa inseriamo 'Buste' come nome del nuovo indicatore e lasciare Indicatore come tipo di Snippet.

Cliccare OKe verrà creato un nuovo indicatore.

 

È possibile vederlo nell'albero di navigazione, in Snippets -> SQ -> Blocks -> Indicators. Ha una propria cartella denominata 'Envelopes' e il codice dello snippet dell'indicatore si trova nel file Buste.java

La convenzione di StrategyQuant prevede che ogni indicatore si trovi nella propria cartella: questo perché in seguito potremmo voler creare dei segnali per questo indicatore e tutti i relativi snippet si troveranno nella stessa cartella.

Questa azione crea un nuovo file per il nostro indicatore Envelopes e lo apre nell'editor. Si può notare che l'indicatore è una classe e ha già una certa struttura.

 

Ogni indicatore viene esteso dalla classe IndicatorBlock e deve implementare un metodo:

  • OnBarUpdate() - in cui il valore dell'indicatore viene calcolato e memorizzato in uno dei buffer di output. Viene richiamato per ogni barra del grafico.

 

Quando si controlla il codice sorgente si notano alcune cose.

In primo luogo, gli snippet in StrategyQuant utilizzano spesso le annotazioni @Parameter, @Output, @BuildingBlock: queste annotazioni vengono utilizzate per dichiarare una proprietà speciale di una determinata variabile o classe, ovvero che la variabile è un parametro pubblico o un valore di uscita, o che la classe è un blocco indicatore.

In secondo luogo, una volta creato e compilato un indicatore, lo si può richiamare da altri metodi o indicatori utilizzando Indicators.YourIndicator(YourIndicatorParameters). Questo è il modo in cui un indicatore può essere richiamato da un altro - lo utilizzeremo anche negli Inviluppi per richiamare gli indicatori della media mobile, ma lo faremo più avanti.

 

Esamineremo passo dopo passo il codice sorgente della classe indicatore predefinita creata dal modello:

package SQ.Blocks.Indicators.Envelopes;

import com.strategyquant.lib.*;
import com.strategyquant.datalib.*;
import com.strategyquant.tradinglib.*;

import SQ.Internal.IndicatorBlock;

questa è la dichiarazione standard di Java di un pacchetto e dell'importazione delle classi necessarie, quelle che usiamo nella nostra classe.


@BuildingBlock(name="(XXX) Envelopes", display="Envelopes(#Period#)[#Shift#]", returnType = ReturnTypes.Price)
@Help("Envelopes help text")
public class Envelopes extends IndicatorBlock {

Definizione annotata della nostra classe indicatore, che indica al sistema che si tratta di un blocco di costruzione con un nome dato.

  • nome è quello che viene visualizzato nell'interfaccia utente quando si scelgono i blocchi di costruzione.
  • display è quello che viene visualizzato nella procedura guidata con i parametri. È possibile controllare quali parametri vengono visualizzati e in quale posizione.
  • returnType è un tipo di indicatore, dice che tipo di valore calcola questo indicatore. Viene utilizzato affinché StrategyQuant sappia quali tipi di indicatori devono essere confrontati con quali. Ad esempio, non confronterebbe il CCI (che restituisce un numero) con le Bande di Bolinger (che restituiscono un prezzo).

 

Esistono fondamentalmente tre tipi di ritorno che un indicatore può avere:

  • Prezzo - L'indicatore calcola il prezzo e viene visualizzato sul grafico del prezzo, come le bande di Bollinger, la media mobile, ecc.
  • Numero - L'indicatore calcola un numero che viene visualizzato sul proprio grafico, come CCI, RSI, MACD, ecc.
  • Fascia di prezzo - L'indicatore calcola l'intervallo di prezzo (differenza tra due prezzi), come l'ATR.

Altri tipi di ritorno sono utilizzati in altri tipi di blocchi di costruzione.

 

Nel nostro caso, Envelopes viene calcolato a partire dalla media mobile di un prezzo, quindi viene visualizzato sul grafico del prezzo. Ciò significa che il suo tipo di ritorno è Price.

 

@Parameter
public DataSeries Input;

@Parameter(defaultValue="10", isPeriod=true, minValue=2, maxValue=1000, step=1)
public int Period;

@Output
public DataSeries Value;

i parametri che seguono sono quelli dell'indicatore. Ogni indicatore può avere più parametri di input; il modello ne crea solo due a titolo di esempio. Ogni parametro è annotato con @Parametro che può avere diversi attributi.

Il primo parametro è Ingressoè l'array di serie di dati da cui viene calcolato l'indicatore - può essere, ad esempio, il prezzo Open, High, Low o Close.

Il secondo parametro è PeriodoGli indicatori hanno di solito un periodo su cui sono calcolati.

La terza variabile è Valore, si noti che ha un'annotazione diversa @Output. Ciò significa che questa variabile non è un parametro dell'indicatore, ma il suo buffer di uscita. Di solito gli indicatori hanno un solo buffer di uscita, ma possono averne di più, ad esempio la banda di Bollinger ha un buffer superiore e uno inferiore.

C'è un altro parametro nascosto Turno - è presente di default in ogni indicatore e indica al motore di trading quale valore deve cercare. In genere non è necessario preoccuparsi di questo parametro, che viene utilizzato automaticamente.

 

Poi c'è un metodo:

protected void OnBarUpdate() throws TradingException {...}

 

Questo è il metodo in cui vengono calcolati i valori degli indicatori. Viene chiamato internamente da SQ per ogni barra e deve calcolare il valore dell'indicatore per questa barra e salvarlo nel buffer di output.

Questo è il codice sorgente del modello di indicatore standard. Nel prossimo passo mostreremo le modifiche da apportare per implementare il nostro indicatore Envelopes.

 

Modifica del modello predefinito generato e implementazione dell'indicatore

L'indicatore creato al punto 1 è un modello di indicatore standard, che non calcola ancora gli Inviluppi. Per implementarlo dobbiamo fare alcune cose:

Aggiornare la sua annotazione @BuildingBlocks

Aggiorneremo l'annotazione di questo indicatore come segue:

@BuildingBlock(name="(EP) Envelopes", display="Envelopes(#MA_Period#, #Deviation#)[#Shift#]", returnType = ReturnTypes.Price)
@Help("Envelopes indicator")
public class Envelopes extends IndicatorBlock {

Questa è la parte più semplice. Ci limiteremo ad aggiornare nome dell'indicatore e aggiungere i nuovi parametri attuali (vedi sotto) al file display attributo.

 

Definire i suoi parametri reali

La prima cosa da fare è un po' complicata: dobbiamo cambiare il tipo del file predefinito Ingresso parametro. Nel modello standard è definito come segue:

@Parameter
public DataSeries Input;

è un parametro chiamato Ingresso, con tipo Serie di dati. Questo vale per gran parte degli indicatori che vengono calcolati a partire da un solo prezzo. Ad esempio, gli indicatori CCI, RSI, ecc. sono solitamente calcolati a partire dal prezzo di chiusura. È possibile configurarli in modo che vengano calcolati da un prezzo diverso, ad esempio dal prezzo di apertura, ma si tratta comunque di un solo array di prezzi.

 

Il tipo DataSeries è un tipo di array di valori che contiene i valori dei prezzi di chiusura, o dei prezzi di apertura, o dei prezzi tipici, ecc.
Tuttavia, se si esamina il codice sorgente di Envelopes MQL, si vedrà che calcola i suoi valori a partire da uno dei valori di prezzo e dal Volume.

 

Per poter accedere a più array di prezzi contemporaneamente, utilizzeremo tipi diversi per l'output:

@Parameter
public ChartData Input;


GraficoDati
 è un oggetto che rappresenta l'intero grafico - si avrà accesso ai prezzi Open, High, Low, Close, Volume nel grafico dato. Questo ci serve per poter calcolare l'indicatore in base al parametro Prezzo applicato.

 

Nota rapida: la scelta del tipo giusto di variabile dei dati di input non è difficile:
Se l'indicatore è calcolato a partire da un prezzo e non è possibile scegliere il prezzo applicato, continuare a utilizzare DataSeries.
Se viene calcolato da più prezzi o se c'è una scelta, ad esempio High, Low, Close, ecc. - utilizzare ChartData.

 

Ci sono poi altri parametri indicatori:

@Parameter(defaultValue="14", isPeriod=true, minValue=2, maxValue=1000, step=1)
public int MA_Period;

MA_Period è un parametro di periodo "standard" per questo indicatore.


@Parameter(defaultValue="0", minValue=0, maxValue=10, step=1)
public int MA_Moved;

MA_Moved è lo spostamento di questo indicatore. Nel codice MQL questo parametro si chiama MA_Shift, ma Shift è una parola riservata in SQ, quindi dobbiamo rinominarlo.

 

@Parameter(name="Method", defaultValue="0")
@Editor(type=Editors.Selection, values="Simple=0,Exponential=1,Smoothed=2,Linear weighted=3")
public int MA_Method;

Questo parametro è il metodo della media mobile. È un po' più complesso, perché definiamo un elenco di selezione (casella combinata) come controllo di modifica di questo parametro. In questo modo, durante la modifica in Wizard, l'utente potrà scegliere tra i valori predefiniti.

 

@Parameter(defaultValue="0")
@Editor(type=Editors.Selection, values="Close=0,Open=1,High=2,Low=3,Median=4,Typical=5,Weighted=6")
public int Applied_Price;

Lo stesso vale per Applied_Price: si tratta di una scelta di ingressi che possono essere utilizzati per calcolare gli Inviluppi.

 

@Parameter(defaultValue="0.1", minValue=0.01, maxValue=10, step=0.01, builderMinValue=0.05, builderMaxValue=1, builderStep=0.05)
public double Deviation;

La deviazione è l'ultimo parametro di ingresso dell'indicatore Inviluppi.

 

Si noti che per questi parametri sono stati specificati anche i valori di min, max e step.

valore minimo/valore massimo sono gli intervalli minimo/massimo che si possono impostare.

valore minimo del costruttore/valore massimo del costruttore sono intervalli opzionali che il costruttore di SQ utilizzerà per la generazione delle strategie; possono essere più piccoli degli intervalli massimi definiti in minValue/maxValue

valore predefinito definisce il valore predefinito di questo indicatore.

passo/costruttorePasso definisce il passo del valore del parametro

 

Definire le uscite

L'indicatore Envelopes ha due uscite - Upper e Lower - e si possono vedere due linee diverse nel grafico MT4.

Quindi dobbiamo definire anche due uscite:

@Output(name="Upper", color=Colors.Green)
public DataSeries Upper;

@Output(name="Lower", color=Colors.Red)
public DataSeries Lower;

L'annotazione @Output significa che si tratta di un buffer di uscita per questo indicatore. Si noti che è di tipo DataSeries, ossia un array di valori doppi.

 

Implementare il metodo OnBarUpdate()

Se guardate il codice MQL di Envelopes vedrete che è abbastanza semplice, il suo codice MQL è:

  int start()
  {
   int limit;
   if(Bars<=MA_Period) return(0);
   ExtCountedBars=IndicatorCounted();
//---- check for possible errors
   if (ExtCountedBars<0) return(-1);
//---- last counted bar will be recounted
   if (ExtCountedBars>0) ExtCountedBars--;
   limit=Bars-ExtCountedBars;
//---- EnvelopesM counted in the buffers
   for(int i=0; i<limit; i++)
     { 
      ExtMapBuffer1[i] = (1+Deviation/100)*iMA(NULL,0,MA_Period,0,MA_Method,Applied_Price,i);
      ExtMapBuffer2[i] = (1-Deviation/100)*iMA(NULL,0,MA_Period,0,MA_Method,Applied_Price,i);
     }
//---- done
   return(0);
  }

Se lo analizzate un po', vedrete che i valori superiore e inferiore sono calcolati con una semplice formula:

Banda superiore = [1+DEVIAZIONE/100] * MA(PREZZO, PERIODO)
Banda inferiore = [1-DEVIAZIONE/100] * MA(PREZZO, PERIODO)

dove i parametri DEVIATION, MA ,PRICE e PERIOD sono configurabili.

 

Possiamo implementarlo in Java in questo modo:

    @Override
    protected void OnBarUpdate() throws TradingException {
        double ma = computeMA();
        Upper.set( (1+Deviation/100d) * ma );
        Lower.set( (1-Deviation/100d) * ma );
    }

 

Metodo OnBarUpdate() viene richiamato per ogni barra del grafico. Il suo compito è quello di calcolare i valori dell'indicatore su questa barra e di memorizzarli nei buffer di uscita.

Quindi nel nostro caso calcoleremo i valori superiore e inferiore per la barra attuale e li memorizzeremo nei rispettivi buffer chiamando Upper.set(), Inferiore.set().

 

Si noti che si utilizza un metodo speciale di aiuto computeMA() per calcolare la media mobile in base ai parametri MA_Method e Applied_Price.

Il codice di questo metodo helper è:

private double computeMA() throws TradingException {
  DataSeries MAInput;

  switch(Applied_Price){
    case 0: MAInput = Input.Close; break;
    case 1: MAInput = Input.Open; break;
    case 2: MAInput = Input.High; break;
    case 3: MAInput = Input.Low; break;
    case 4: MAInput = Input.Median; break;
    case 5: MAInput = Input.Typical; break;
    default: throw new TradingException(String.format("Undefined Applied price: %d !", Applied_Price));
  }

  switch(MA_Method){
    case 0: return Indicators.SMA(MAInput, MA_Period).Value.get(MA_Moved);
    case 1: return Indicators.EMA(MAInput, MA_Period).Value.get(MA_Moved);
    case 2: return Indicators.SMMA(MAInput, MA_Period).Value.get(MA_Moved);
    case 3: return Indicators.LWMA(MAInput, MA_Period).Value.get(MA_Moved);
    default: throw new TradingException(String.format("Undefined MA Method: %d !", MA_Method));
  }
}

È un po' più lungo, ma comprensibile. Per prima cosa sceglieremo i dati di prezzo corretti in base a Prezzo_applicato parametro.

Nel secondo passo chiameremo l'indicatore di media mobile appropriato su questo input, in base a Metodo MA parametro.

 

Analizziamo ad esempio una delle chiamate: Indicators.SMA(MAInput, MA_Period).Value.get(MA_Moved):

  • Indicators.SMA(MAInput, MA_Period) richiama l'indicatore SMA sull'ingresso MAInput con MA_Period. L'indicatore SMA ha un solo buffer di uscita chiamato Valore, quindi i valori calcolati dell'indicatore saranno memorizzati lì.
  • otterremo il buffer semplicemente chiamando .Valore
  • Il valore è un buffer (di tipo DataSeries), come i buffer superiore e inferiore, cioè un array di valori doppi, dove ogni valore appartiene a una barra del grafico. Per ottenere il valore della barra nella posizione N, si deve chiamare Value.get(N).
    Nel nostro caso chiameremo .Value.get(MA_Moved)perché vogliamo che il valore si sposti facoltativamente indietro di alcune barre, in base al parametro MA_Moved.

 

Quindi l'intera chiamata Indicators.SMA(MAInput, MA_Period).Value.get(MA_Moved) calcolerà la SMA con periodo Periodo MA sul Ingresso MA e restituisce il suo valore MA_Spostamento bar fa.

 

Si noti che i valori nel buffer di uscita sono indicizzati a partire da zero, dove zero è il valore della barra più recente.

Quindi:

  • Value.get(0) - restituisce il valore della barra corrente
  • Value.get(1) - restituisce il valore della barra precedente
  • Value.get(2) - restituisce il valore della barra precedente e così via.

 

Questo è tutto, ora quando colpiamo Compilazione e poi riavviare SQ per vedere il nostro nuovo indicatore Envelopes nella sezione Random Indicators Signals.

 

Codice sorgente completo del nostro nuovo indicatore - è possibile scaricarlo anche in allegato a questo articolo:

package SQ.Blocks.Indicators.Envelopes;

import com.strategyquant.lib.*;
import com.strategyquant.datalib.*;
import com.strategyquant.tradinglib.*;

import SQ.Internal.IndicatorBlock;

/**
 * Indicator name as it will be displayed in UI, and its return type.
 * Possible return types:
 * ReturnTypes.Price - indicator is drawn on the price chart, like SMA, Bollinger Bands etc.
 * ReturnTypes.Price - indicator is drawn on separate chart, like CCI, RSI, MACD
 * ReturnTypes.PriceRange - indicator is price range, like ATR.
 */
@BuildingBlock(name="(EP) Envelopes", display="Envelopes(#MA_Period#, #Deviation#)[#Shift#]", returnType = ReturnTypes.Price)
@Help("Envelopes indicator")
public class Envelopes extends IndicatorBlock {

  @Parameter
  public ChartData Input;

  @Parameter(defaultValue="14", isPeriod=true, minValue=2, maxValue=1000, step=1)
  public int MA_Period;

  @Parameter(defaultValue="0", minValue=0, maxValue=10, step=1)
  public int MA_Moved;

  @Parameter(name="Method", defaultValue="0")
  @Editor(type=Editors.Selection, values="Simple=0,Exponential=1,Smoothed=2,Linear weighted=3")
  public int MA_Method;

  @Parameter(defaultValue="0")
  @Editor(type=Editors.Selection, values="Close=0,Open=1,High=2,Low=3,Median=4,Typical=5,Weighted=6")
  public int Applied_Price;
  
  @Parameter(defaultValue="0.1", minValue=0.01, maxValue=10, step=0.01, builderMinValue=0.05, builderMaxValue=1, builderStep=0.05)
  public double Deviation;

  @Output(name="Upper", color=Colors.Green)
  public DataSeries Upper;

  @Output(name="Lower", color=Colors.Red)
  public DataSeries Lower;

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

  @Override
  protected void OnBarUpdate() throws TradingException {
    double ma = computeMA();

    Upper.set( (1+Deviation/100d) * ma );
    Lower.set( (1-Deviation/100d) * ma );
  }

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

  private double computeMA() throws TradingException {
    DataSeries MAInput;

    switch(Applied_Price){
      case 0: MAInput = Input.Close; break;
      case 1: MAInput = Input.Open; break;
      case 2: MAInput = Input.High; break;
      case 3: MAInput = Input.Low; break;
      case 4: MAInput = Input.Median; break;
      case 5: MAInput = Input.Typical; break;
      default: throw new TradingException(String.format("Undefined Applied price: %d !", Applied_Price));
    }

    switch(MA_Method){
      case 0: return Indicators.SMA(MAInput, MA_Period).Value.get(MA_Moved);
      case 1:	return Indicators.EMA(MAInput, MA_Period).Value.get(MA_Moved);
      case 2: return Indicators.SMMA(MAInput, MA_Period).Value.get(MA_Moved);
      case 3: return Indicators.LWMA(MAInput, MA_Period).Value.get(MA_Moved);
      default: throw new TradingException(String.format("Undefined MA Method: %d !", MA_Method));
    }
  }
}

 

 

Test del nuovo indicatore in SQ X rispetto ai dati di MT

abbiamo appena creato (o stiamo sviluppando) il nostro nuovo indicatore. Come facciamo a sapere se lo abbiamo implementato correttamente?

Una volta creato il nuovo indicatore in StrategyQuant e compilato con successo, è necessario verificare se funziona davvero come in MetaTrader, ovvero se i valori calcolati da esso sono gli stessi di quelli in MT4.

 

A tal fine, nell'Editor del codice è disponibile uno strumento di verifica degli indicatori. Funziona semplicemente confrontando i valori calcolati in SQ con quelli calcolati in MT4.

 

In generale, funziona in pochi e semplici passaggi:

  1. Utilizzare lo script di aiuto per calcolare ed esportare i dati degli indicatori in MetaTrader
  2. Copiare i file di dati calcolati nella posizione corretta in modo che SQ possa trovarli.
  3. Configurare ed eseguire il test dell'indicatore in SQ

Utilizzare lo script di aiuto per calcolare ed esportare i dati degli indicatori in MetaTrader

Come primo passo dobbiamo preparare i dati di test della MT4 - dobbiamo calcolare l'indicatore su un certo numero di barre e salvare i valori calcolati in un file.

Per questo forniamo un semplice EA che potete utilizzare: si trova in {SQ}/custom_indicators/MetaTrader4/Experts/SqIndicatorValuesExportEA.mq4

 

Aggiungete questo EA alla vostra MetaTrader, modificatelo per calcolare il valore di uscita del vostro indicatore ed eseguitelo in MT4 StrategyTester su qualsiasi dato - per fare un test ottimale dovrebbe essere eseguito su almeno 1000 barre.

 

Poiché Envelopes ha due buffer di uscita, dobbiamo eseguirlo due volte: una volta per il buffer superiore e una per quello inferiore.

Ecco il codice modificato di questo script di esportazione che calcola l'indicatore degli inviluppi:

//+------------------------------------------------------------------+
//|                                   SQ_IndicatorValuesExportEA.mq4 |
//|                                                                  |
//|                    EA to export indicator values from MetaTrader |
//|                Output to: /{Data folder}/tester/files/******.csv |
//+------------------------------------------------------------------+

#property copyright "Copyright © 2019 StrategyQuant"
#property link      "https://strategyquant.com"

string currentTime = "";
string lastTime = "";

//+------------------------------------------------------------------+

int start() {
   currentTime = TimeToStr(Time[1], TIME_DATE|TIME_MINUTES|TIME_SECONDS);
   if(currentTime == lastTime) {
      return(0);
   }
   
   double value;

   // change the file name below
   string fileName = "Envelopes_14_0_0_0_0.1_upper.csv";

   int handle = FileOpen(fileName, FILE_READ | FILE_WRITE, ";");
   if(handle>0) {
      FileSeek(handle,0,SEEK_END);

      // here is the indicator value 
      value = iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0.1 , 1 , 1); // upper value
      //value = iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0.1 , 2 , 1); // lower value
      
      FileWrite(handle, TimeToStr(Time[1], TIME_DATE|TIME_MINUTES|TIME_SECONDS), Open[1], High[1], Low[1], Close[1], Volume[1], value);
      FileClose(handle);
   }

   lastTime = currentTime;
   return(0);
}

calcolerà l'indicatore degli inviluppi su MT4 chiamando il suo metodo interno iEnvelopes() con i parametri appropriati.

Si noti che i parametri possono essere configurati, non è necessario utilizzare quelli predefiniti. È buona norma includere i valori dei parametri anche nel nome del file di dati di output, come nel nostro caso "Envelopes_14_0_0_0.1_upper.csv", in modo da sapere che è stato generato con questi parametri.

Ora possiamo eseguire questo script due volte in MT Tester:

Al termine dovrebbe creare un file di dati con i valori calcolati dell'indicatore e i prezzi Open, High, Low, Close per ogni barra. Il file verrà salvato in MetaTrader4 -> {cartella dati}/tester/files/nome_tuo_file.csv


Dovremmo vedere due file:
Envelopes_14_0_0_0_0.1_upper.csv
Envelopes_14_0_0_0_0.1_lower.csv

 

Copiare i file di dati calcolati nella posizione corretta in modo che SQ possa trovarli.


Copiare questi file in una cartella
{installazione SQ}/test/Indicatori/MetaTrader4

Creare questa cartella se non esiste, SQ Indicaotrs Tester cerca i file in questa cartella.

Ora che abbiamo preparato il file di dati, iniziamo un test in StrategyQuant.

 

Configurare ed eseguire il test dell'indicatore in SQ

Nell'Editor di codice, fare clic su Indicatori di prova nella barra degli strumenti.

Si aprirà la finestra di dialogo Indicator Tester, fare clic su Aggiungere un nuovo test. Aggiungere gli indicatori delle buste al test, sia per l'uscita superiore che per quella inferiore.

Lo si vedrà nella tabella seguente. L'ultima cosa da fare è modificare il file Nome del file di provain base ai nomi dei file dei dati di prova creati nel passaggio precedente e, facoltativamente, anche Parametri del test, se si sono usati altri tipi di dati oltre a quelli predefiniti:

Al termine, fare clic su Inizio per eseguire i test.

Nel caso ideale i test avranno successo e i valori calcolati in SQ corrisponderanno ai valori calcolati in MT4:

Se qualcosa non funziona, ci saranno differenze tra i valori di SQ e MT4. È possibile fare clic sul messaggio delle differenze per visualizzarle nell'elenco:

Se il test fallisce, verificare innanzitutto se i dati di test generati in MT4 utilizzavano gli stessi parametri dell'indicatore, perché potrebbe esserci un errore.

Se i dati del test sono corretti, c'è qualcosa che non va nell'implementazione SQ dell'indicatore: funziona in modo diverso dalla sua controparte MT4 e deve essere corretto.

 

Aggiunta della traduzione del blocco Indicatore nella lingua della piattaforma di destinazione

Ora l'indicatore funziona correttamente in StrategyQuant. È possibile utilizzarlo per generare strategie basate su di esso o utilizzarlo in AlgoWizard. Ma non abbiamo ancora finito.

Se si accede al codice sorgente della strategia, si vedrà un messaggio di errore come questo:

Significa che quando si genera il codice Pseudo Code / MT4 / MT5 o Tradestation, StrategyQuant non riesce a trovare un modello che traduca il blocco dal formato XML interno di SQ al linguaggio della piattaforma di destinazione.


Finora abbiamo creato un codice per gli Inviluppi da calcolare all'interno di StrategyQuant. Ma StrategyQuant non sa come tradurre questo indicatore in un codice nella vostra piattaforma di trading: dipende dalla piattaforma stessa.

In StrategyQuant, le strategie generate sono salvate internamente in formato XML. Quando si passa a Strategy XML e si cerca l'indicatore Envelopes, si vedrà che è salvato in questo modo:

<Item key="IsGreater" name="(&gt;) Is greater" display="#Left# &gt; #Right#" mI="Comparisons" returnType="boolean" categoryType="operators">
  <Block key="#Left#">
    <Item key="Envelopes" name="(EP) Envelopes" display="Envelopes(#Period#)[#Shift#]" help="Envelopes help text" mI="Envelopes" returnType="price" categoryType="indicator">
      <Param key="#Chart#" name="Chart" type="data" controlType="dataVar" defaultValue="0">0</Param>
      <Param key="#MA_Period#" name="MA _ Period" type="int" defaultValue="14" genMinValue="-1000003" genMaxValue="-1000004" paramType="period" controlType="jspinnerVar" minValue="2" maxValue="1000" step="1" builderStep="1">14</Param>
      <Param key="#MA_Moved#" name="MA _ Moved" type="int" defaultValue="0" controlType="jspinnerVar" minValue="0" maxValue="10" step="1" builderStep="1">0</Param>
      <Param key="#MA_Method#" name="Method" type="int" defaultValue="0" controlType="combo" values="Simple=0,Exponential=1,Smoothed=2,Linear weighted=3" builderStep="1">0</Param>
      <Param key="#Applied_Price#" name="Applied _ Price" type="int" defaultValue="0" controlType="combo" values="Close=0,Open=1,High=2,Low=3,Median=4,Typical=5,Weighted=6" builderStep="1">0</Param>
      <Param key="#Deviation#" name="Deviation" type="double" defaultValue="0.1" controlType="jspinnerVar" minValue="0.01" maxValue="10" step="0.01" builderMinValue="0.05" builderMaxValue="1" builderStep="0.05">0.1</Param>
      <Param key="#Shift#" name="Shift" type="int" defaultValue="1" controlType="jspinnerVar" minValue="0" maxValue="1000" genMinValue="-1000001" genMaxValue="-1000002" paramType="shift" step="1" builderStep="1">1</Param>
      <Param key="#Line#" name="Line" type="int" controlType="combo" values="Upper=0,Lower=1" defaultValue="0">0</Param>
    </Item>
  </Block>
  <Block key="#Right#">
    <Item key="Number" name="(NUM) Number" display="#Number#" help="Number constant" mI="Other" returnType="number" categoryType="other" notFirstValue="true">
      <Param key="#Number#" name="Number" type="double" defaultValue="0" controlType="jspinner" minValue="-999999999" maxValue="999999999" step="1" builderStep="1">0</Param>
    </Item>
  </Block>
</Item>

Questa è solo una parte dell'XML della strategia che contiene il confronto delle buste con il numero. Si noti che utilizza i blocchi () È più grande, Buste, Numero.

SQ cercherà dei modelli per tradurre ciascuno dei blocchi XML nella lingua della piattaforma di destinazione. Modelli per È più grande e Numero sono presenti per impostazione predefinita nel sistema, ma manca un modello per Buste.

 

I modelli sono memorizzati in Codice sottoalbero. Qui, ogni piattaforma supportata ha una propria cartella, al cui interno si trova una sottocartella /blocchi che contiene modelli per ogni blocco di costruzione.

 

I file modello hanno .tpl e sono molto semplici. Utilizzano il motore di template Freemarker (https://freemarker.apache.org) per tradurre l'XML dell'indicatore nel codice della piattaforma di destinazione.

Si noti che i modelli NON contengono il codice per calcolare l'indicatore nella piattaforma di destinazione, contengono il codice per CHIAMATA l'indicatore.

Se si controlla, si vedrà che non c'è il template Envelopes.tpl, quindi il codice sorgente mostra un messaggio che indica che il template è mancante.

Aggiunta del modello di pseudocodice per un nuovo blocco

Quando si guarda l'Envelopessnippet nella finestra Navigator, si noterà che c'è un'icona di errore e, passandoci sopra con il mouse, si vedrà il messaggio di errore: manca il codice del template per ogni piattaforma di destinazione.

 

Il modo più semplice per aggiungerlo è quello di fare clic sul file Envelopes.java con il tasto destro del mouse per aprire il menu a tendina e lì
scegliere l'azione
Aggiungere tutti i dati mancanti.

Questo aggiungerà modelli predefiniti per tutte le piattaforme di destinazione.
Quando si va in Codice -> Pseudo codice -> Blocchi, si vedrà che è stato aggiunto il template Buste.tpl con alcuni contenuti predefiniti.

Si può notare che il template è abbastanza semplice, di solito è una sola riga.

 

Ora che il modello è presente, è possibile controllare nuovamente il codice sorgente della strategia.


È possibile vedere che il codice sorgente è stato prodotto, ma non è realmente corretto. 

Mostra Buste(grafico principale, , , 1) invece dei parametri reali di Envelopes. Il motivo è che Envelopes.tpl è stato creato utilizzando il modello predefinito e non ha utilizzato i parametri reali degli indicatori.

Se si controlla il codice PseudoCode/blocks/Envelopes.tpl, si vedrà che è come segue:

Envelopes( , , )

I metodi printInput e printShift sono metodi predefiniti per stampare i valori di input dei dati e di spostamento e funzionano correttamente per impostazione predefinita, perché ogni indicatore ha alcuni input di grafico/dati e spostamenti.

Ma nel nostro indicatore non abbiamo parametri denominati Param1 e Param2. 

Al suo posto abbiamo altri cinque parametri: MA_Period, MA_Moved, MA_Method, Applied_Price, Deviation.

 

Quindi modificheremo il modello in questo modo:

Buste( , , , , )

 

Ora, se si osserva lo pseudocodice, si vedrà che viene visualizzato con i valori corretti dei parametri:

Come si può vedere, la stampa di un parametro in un modello è molto semplice: basta usare il metodo:

<@printParam block “#PARAMETER_NAME#” />

dove NOME PARAMETRO è il nome della variabile parametro del codice Java.


C'è ancora una cosa che può essere migliorata: i parametri. Metodo MA e Prezzo_applicato sono visualizzati come numeri - noi vorremmo visualizzarli come testi, in modo da sapere quali valori sono stati selezionati.

Per farlo, possiamo utilizzare il metodo:

<@printParamOptions block “# PARAMETER_NAME #” “0=Option1,1=Option2,3=Option3” />


Questo metodo tradurrà il valore numerico dell'opzione in base al suo numero.

Inoltre, per non essere sommersi da informazioni poco importanti, non è necessario visualizzare il valore del parametro MA_Moved nel codice Pseud. Possiamo semplicemente eliminarlo dal modello.

Quindi il nostro codice modello finale di PseudoCodice per le buste in PseudoCodice sarà il seguente:

Envelopes( , , , )

e produrrà un risultato come questo:

 

Aggiunta del modello MetaTrader 4 per il nuovo blocco

Nella fase precedente abbiamo aggiunto un modello di Pseudo Codice per il nostro indicatore Envelopes, in modo da poter vedere le regole della strategia in Pseudo Codice.

Questo passaggio deve essere ripetuto per ogni piattaforma target su cui si desidera utilizzare la strategia. 

Quindi sistemiamo il modello per MetaTrader MQL. Ci sono due possibilità in MetaTrader:

  • o l'indicatore è incorporato in MetaTrader e quindi possiamo chiamarlo utilizzando la sua funzione MQL,
  • oppure si tratta di un indicatore personalizzato e dobbiamo chiamarlo con la chiamata iCustom MQL.

Mostreremo entrambi i modi, che differiscono solo leggermente nel codice del modello.

 

Prima possibilità: l'indicatore è integrato in MetaTrader

In questo caso si può trovare l'indicatore nell'elenco degli indicatori disponibili nel navigatore MT4 e si può
è possibile trovare il metodo per chiamarlo anche nella Guida di riferimento MQL:

Dalla documentazione MQL sappiamo che quando si richiama questo indicatore si deve chiamare la funzione iInvolucri() con i parametri giusti.

Apriamo quindi il file Code / MetaTrader4 / blocks / Envelopes.tpl e modifichiamolo come segue:

iEnvelopes(, , , , , , +1, )

Abbiamo rinominato il metodo e aggiunto i parametri corretti. I metodi printInput e printShift producono un output corretto per impostazione predefinita.

Si noti un altro parametro - Linea. Poiché le buste hanno due righe (superiore e inferiore), anche la chiamata a iEnvelopes consente di specificare il valore della riga che si desidera recuperare: è l'ottavo parametro. modalità, che è l'indice della linea.

Questo parametro in MQL è 1 per Upper o 2 per Lower.

Linea è anch'esso creato di default da SQ, basta controllare l'XML di questo blocco. Ma è basato su zero e l'indice di riga dipende dall'ordine delle variabili @Output definite nella classe Java. Quindi in SQ 0 = superiore, 1 = inferiore. Per ottenere gli stessi valori di MT4, dobbiamo aggiungere 1 al valore della riga.

 

Quando andiamo nel codice sorgente di MT4 vediamo che ha prodotto questo output:

Qual è il modo corretto di chiamare l'indicatore Envelopes in MQL? .

 

Seconda possibilità: si tratta di un indicatore personalizzato (esterno) per MetaTrader.

E se l'indicatore non è integrato in Metatrader? La situazione è solo leggermente più complicata.
Per esempio, supponiamo che l'indicatore Envelopes non esista in MT4 e che dobbiamo utilizzarlo come indicatore personalizzato.


Per prima cosa, scaricare l'indicatore Buste da questo link: https://www.mql5.com/en/code/7975
 e salvarlo in un file all'indirizzo {MT4} -> Cartella dati/MQL/Indicatori/Buche.mq4

In questo modo diventerà disponibile in MetaTrader e potrà essere utilizzato e richiamato. 

 

Gli indicatori personalizzati vengono richiamati tramite la funzione MQL iCustom:

Quindi la chiamata corretta dell'indicatore personalizzato Envelopes in MQL sarebbe:

iCustom(Symbol, Timeframe, "Envelopes", MA_Period, MA_Moved, MA_Method, Applied_Price, Deviation, 1, Shift)

per ottenere la linea Upper e

iCustom(Symbol, Timeframe, "Envelopes", MA_Period, MA_Moved, MA_Method, Applied_Price, Deviation, 2, Shift)

per ottenere la linea inferiore.

Definiamo il nostro modello come segue:

iCustom(, "Envelopes", , , , , , +1, )

 

che produce nuovamente un codice MQL corretto, utilizzando una chiamata all'indicatore personalizzata:

 

L'unica differenza rispetto all'opzione precedente è che non utilizziamo il metodo MQL predefinito iEnvelopes, ma un metodo generale iCustom che ci consente di richiamare qualsiasi indicatore personalizzato esterno.

 

 

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

Abbonarsi
Notificami
2 Commenti
Il più vecchio
Più recente I più votati
Feedback in linea
Visualizza tutti i commenti
dorsler
dorsler
26. 10. 2020 16:20

Grazie Marc
Guardando solo l'indicatore delle buste che cerca di estrarre questo in SQ dall'articolo che hai scritto
https://strategyquant.com/doc/programming-sq/adding-envelopes-indicator-step-by-step
Il file CSV generato di seguito restituisce solo un singolo file nel file del tester MT4 quando l'indicatore ha eseguito il test.
// cambiare il nome del file sotto  
stringa fileName = “Envelopes_14_0_0_0_0.1_upper.csv”;
SQ sarà ancora in grado di leggere i valori superiori e inferiori o è necessaria un'altra riga di codice?
Questo indicatore mi piace molto e sarà una buona aggiunta alla libreria di test.
Grazie
Dave

tomas262
tomas262
Rispondi a  dorsler
30. 10. 2020 7:39 pm

È necessario esportare 2 file CSV separati. Uno contenente i valori per la busta superiore utilizzando questo codice = iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0.1 , 1 , 1); quindi esportare un altro file CSV con i valori per la busta inferiore utilizzando il codice = iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0.1 , 2 , 1); notare i valori modificati al numero 2 utilizzati nella penultima posizione della seconda riga di codice. Ora sono disponibili 2 file CSV: Buste_14_0_0_0.1_upper.csv e Buste_14_0_0_0.1_lower.csv.... Leggi il resto "

Ultima modifica 3 anni fa da tomas262