Documentazione

Applicazioni

Ultimo aggiornamento il 18. 5. 2020 da Mark Fric

Indicatore ForceIndex

Vediamo come aggiungere un nuovo indicatore personalizzato in StrategyQuant X. A differenza di SQ3, SQX consente di estendere il programma creando indicatori e blocchi personalizzati, in modo simile a come è possibile aggiungere nuovi indicatori alle normali piattaforme di trading come MetaTrader 4/5, Tradestation e così via.

Vi illustreremo il processo passo dopo passo per spiegarvi tutto ciò che è necessario.

Alla fine avremo un nuovo indicatore personalizzato aggiunto a StrategyQuant e potrete aggiungerlo all'elenco dei blocchi per la generazione di strategie.

Utilizzeremo Indice di forza un esempio di indicatore. Questo indicatore è già integrato in Metatrader; il suo codice sorgente è disponibile qui: https://www.mql5.com/en/code/8013

Ecco come appare l'indicatore sul grafico:

 

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

  1. Aggiunta di un nuovo blocco di indicatori
  2. (Facoltativo, consigliato) Test del nuovo indicatore in SQ X rispetto ai dati di MT
  3. (Opzionale, consigliato) Aggiunta di nuovi blocchi di segnali basati sull'indicatore
  4. Aggiunta della traduzione del blocco Indicatore nella lingua della piattaforma di destinazione

 

Passo 1 - Creare un nuovo indicatore personalizzato nell'Editor del codice

Il primo passo consiste nel creare il nostro indicatore in Code Editor. StrategyQuant utilizza internamente il linguaggio di programmazione Java e gli indicatori personalizzati devono essere programmati in Java.

Non è possibile prendere il codice MQL e copiarlo e incollarlo in StrategyQuant, non funzionerebbe. È necessario riscrivere l'indicatore in linguaggio Java.

Per prima cosa dobbiamo aprire l'Editor di codice:

In Code Editor è possibile creare, modificare e correggere gli snippet, quindi creeremo un nuovo snippet per il nostro nuovo indicatore.

Una volta entrati nell'Editor del codice, facciamo clic sul pulsante Crea nuovo nella barra degli strumenti superiore.

Si aprirà una finestra di dialogo, dove potremo dare un nome al nostro nuovo snippet e sceglierne il tipo. Lo chiameremo "ForzaIndice" e scegliere Indicatore come tipo di snippet.

Dopo aver fatto clic su OK, verrà creata una nuova cartella ForceIndex sotto la voce Snippet -> SQ -> Blocchi -> Indicatori e un nuovo file snippet ForceIndex.java in questa cartella.

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 ForceIndex 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). Ecco come viene chiamato il nostro nuovo indicatore nel metodo OnBlockEvaluate().

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

pacchetto SQ.Blocks.Indicators.ForceIndex;
 
import com.strategyquant.lib.*; import com.strategyquant.datalib.*; import com.strategyquant.tradinglib.*;
 
importare 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) ForceIndex ", display="ForceIndex (#Period#)[#Shift#]", returnType = ReturnTypes.Price)
@Help("Testo di aiuto di ForceIndex")

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 ForceIndex NON viene visualizzato sul grafico dei prezzi, quindi il suo tipo di ritorno è Number, non Price. Lo modificheremo nella fase successiva.

@Parametro pubblico DataSeries Input;
 
@Parametro(defaultValue = "10", isPeriod = true, minValue=1, maxValue=10000, step=1) public int Periodo;
 
@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() {...}

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 ForceIndex.

 

Passo 2 - Modifica del modello predefinito generato e implementazione dell'indicatore

L'indicatore creato nel passo 1 è un modello di indicatore standard, che non calcola ancora il ForceIndex. Per implementare il ForceIndex dobbiamo fare alcune cose:

 

Aggiornare la sua annotazione @BuildingBlocks

Aggiorneremo l'annotazione di questo indicatore come segue:

@BuildingBlock(name="(FI) ForceIndex ", display="ForceIndex (#Nbr_Periods#, #Multiplier)[#Shift#]", returnType = ReturnTypes.Number)

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

Abbiamo anche cambiato returnType in Number, perché questo indicatore calcola i numeri visualizzati sul grafico separato, non emette un valore di prezzo.

 

Definire i parametri di ForceIndex

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

@Parametro pubblico 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 ForceIndex MQL, si vedrà che calcola i suoi valori da uno dei valori di prezzo e dal Volume.

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

@Parametro public ChartData Chart;


GraficoDati
è un oggetto che rappresenta l'intero grafico: si avrà accesso ai prezzi Open, High, Low, Close, Volume nel grafico dato.


Nota rapida: scelta del tipo giusto per la variabile dei dati di input :
Se l'indicatore è calcolato da un prezzo, utilizzare DataSeries.
Se è calcolato da più prezzi, ad esempio High, Low, Close, ecc. - utilizzare ChartData.

C'è poi un parametro Periodo, che possiamo lasciare invariato:

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

Il terzo parametro è il metodo della media mobile:

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

Questo è un po' più complesso, perché definiamo un elenco di selezione (controllo 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.

L'ultimo parametro è il prezzo applicato, ovvero il prezzo da utilizzare nel calcolo della media mobile:

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

Si noti che sono stati utilizzati alcuni attributi nel file @Parametro annotazione:

  • valore predefinito imposta il valore predefinito di questo parametro
  • isPeriod=true indica a SQ che questo parametro è un periodo - vengono gestiti in modo speciale; nella configurazione del costruttore è possibile configurare il valore minimo e massimo per i periodi, quindi SQ deve sapere quali parametri sono periodi.
  • valore minimo, valore massimo, passo sono i valori minimo e massimo che verranno generati per questo parametro durante il processo di generazione casuale.

Definire le uscite ForceIndex

L'indicatore ForceIndex ha una sola uscita, quindi possiamo lasciarlo invariato:

@Output public DataSeries Value;

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 ForceIndex vedrete che è abbastanza semplice, il suo codice MQL è:

int start() {
  int nLimit;
  int nCountedBars=IndicatorCounted();

  //---- dati insufficienti
  if(BarsExtForcePeriod) nCountedBars--;
  nLimit=Barre-nCountedBars;

  //---- Indice di forza contato
  for(int i=0; i<nLimit; i++)
    ExtForceBuffer[i] = Volume[i] * (iMA(NULL,0,ExtForcePeriod,0,ExtForceMethod,ExtForceAppliedPrice,i) - iMA(NULL,0,ExtForcePeriod,0,ExtForceMethod,ExtForceAppliedPrice,i+1));

  //---- fatto
  return(0);
}

Analizzando l'algoritmo, si può notare che il valore dell'indice di forza alla candela data viene calcolato come segue:

ForceIndex[i] = Volume[i] *(MovAvg(Periodo, MAMethod, AppliedPrice)[i] - MovAvg(Periodo, MAMethod, AppliedPrice)
[i+1]

 

Possiamo implementarlo in Java in questo modo:

protected void OnBarUpdate() throws TradingException {
    DataSeries computedFrom = Chart.getSeries(AppliedPrice);
 
    double indiValue = Chart.Volume.get(0) * (Indicators.MA(computedFrom, Period, MAMethod).Value.get(0) - Indicators.MA(computedFrom, Period, MAMethod).Value.get(1));
 
    Value.set(0, indiValue);
} 

In questo caso, l'indicatore è piuttosto semplice e il suo calcolo richiede praticamente una sola riga in StrategyQuant.

Per prima cosa otteniamo il prezzo da cui calcolare l'indicatore - chiamando Chart.getSeries(Prezzo applicato).
Quindi calcoliamo il nuovo valore dell'indicatore come differenza della media del valore del prezzo attuale e di quello precedente moltiplicato per il volume attuale.

 

Questo è tutto, ora quando colpiamo Compilazione e poi riavviare SQ per vedere il nostro nuovo indicatore ForceIndex nella sezione Segnali degli indicatori casuali.

Codice sorgente completo del nostro nuovo indicatore:

pacchetto SQ.Blocks.Indicators.ForceIndex;

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

importare SQ.Internal.IndicatorBlock;

/**
 * Nome dell'indicatore come verrà visualizzato nell'interfaccia utente e tipo di ritorno.
 * Possibili tipi di ritorno:
 * ReturnTypes.Price - l'indicatore viene disegnato sul grafico del prezzo, come SMA, Bande di Bollinger ecc.
 * ReturnTypes.Price - l'indicatore è disegnato su un grafico separato, come CCI, RSI, MACD.
 * ReturnTypes.PriceRange - l'indicatore è un intervallo di prezzi, come ATR.
 */
@BuildingBlock(name="(FI) ForceIndex ", display="ForceIndex (#Period#)[#Shift#]", returnType = ReturnTypes.Number)
@Help("Testo di aiuto di ForceIndex")
public class ForceIndex extends IndicatorBlock {

  @Parametro
  public ChartData Chart;

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

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

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

  @Output
  public DataSeries Value;

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

  /**
   * Questo metodo viene chiamato ad ogni aggiornamento della barra e qui viene calcolato il valore dell'indicatore.
   *
   * A differenza di MT4, non è necessario calcolare i valori dell'indicatore per più barre in un ciclo,
   * è necessario calcolare il valore solo per l'ultima barra (corrente).
   * Il motore di trading si occuperà di richiamare questo metodo per ogni barra del grafico.
   *
   * La barra effettiva per la quale viene calcolato il valore dell'indicatore è memorizzata nella variabile CurrentBar.
   * Se 0, significa che è la prima barra del grafico.
   */
  @Override
  protected void OnBarUpdate() throws TradingException {
    	double indiValue;

    	indiValue = Chart.Volume.get(0) * (Indicators.MA(Chart.Close, Period, MAMethod).Value.get(0) - Indicators.MA(Chart.Close, Period, MAMethod).Value.get(1));

      	Value.set(0, indiValue);
  }

}

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

Abbonarsi
Notificami
5 Commenti
Il più vecchio
Più recente I più votati
Feedback in linea
Visualizza tutti i commenti
Pieter Kotzee
Pieter Kotzee
21. 6. 2020 8:56

Salve, ho copiato il codice esattamente come indicato sopra ma ottengo due errori quando provo a compilare. Entrambi sono alla riga 55 ed entrambi hanno la stessa descrizione. Uno è la colonna 54 e l'altro è la 114:
non trova il simbolo simbolo: metodo MA(com.strategyquant.datalib.Dataseries,int,int) posizione: variabile Indicators di tipo SQ>Internal.Indicators
 

Ultima modifica 3 anni fa da Pieter Kotzee
tomas262
tomas262
Rispondi a  Pieter Kotzee
29. 6. 2020 10:06 pm

Il metodo MA non fa parte del pacchetto. Si prega di trovarlo qui https://strategyquant.com/codebase/forceindex/

Emmanuel2
21. 9. 2021 7:37 pm

Grazie mille, questo esempio è di grande aiuto.

Matteo Nowlis
Matteo Nowlis
26. 2. 2022 7:09 pm

Sono riuscito ad aggiungere il codice java per l'indicatore Force Index e i blocchi di segnale. Il codice viene compilato senza errori. Tuttavia, quando genero strategie in StrategyQuant con l'indicatore, ottengo un errore perché mancano i modelli di codice (MT4, MT5, pseudocodice, ecc.). Nel codice della strategia c'è scritto:

Errore! Uno o più blocchi utilizzati dalla strategia non sono implementati in (MT4, MT5, pseudocodice, ecc.)

Inclusione del template fallita (per valore del parametro "blocchi/ForceIndex.tpl"):
Template non trovato per nome "PseudoCodice/blocchi/ForceIndex.tpl".
Il nome è stato interpretato da questo TemplateLoader: MultiTemplateLoader(loader1 = FileTemplateLoader(baseDir="C:\StrategyQuantX\internal\extend\Code"), loader2 = FileTemplateLoader(baseDir="C:\StrategyQuantX\user\extend\Code")).

—-
Traccia dello stack FTL (“~” significa legato alla nidificazione):
    - Fallito a: #include "blocchi/" + blockKey + ".tpl"  [in modello "PseudoCode/pseudoBlocks.inc" in macro "printBlock" alla linea 122, colonna 20]
    - Raggiunto attraverso: Blocco @printBlock?children[0], shift [in modello "PseudoCode/pseudoBlocks.inc" in macro "printBlock" alla linea 107, colonna 9]
    - Raggiunto attraverso: @printBlock c, shift [in modello "PseudoCode/pseudoBlocks.inc" in macro "printBlockChild" alla linea 148, colonna 14]
    - Raggiunto tramite: Blocco @printBlockChild, "#Sinistra#"  [in modello "PseudoCodice/blocchi/IsGreater.tpl" alla linea 1, colonna 2]
    - Raggiunto tramite: #include "blocchi/" + blockKey + ".tpl"  [in modello "PseudoCode/pseudoBlocks.inc" in macro "printBlock" alla linea 122, colonna 20]
    - Raggiunto attraverso: Blocco @printBlock?children[0], shift [in modello "PseudoCode/pseudoBlocks.inc" in macro "printBlock" alla linea 107, colonna 9]
    - Raggiunto attraverso: Blocco @printBlock [in modello "PseudoCodice/blocchi/AND.tpl" alla linea 5, colonna 38]
    - Raggiunto tramite: #include "blocchi/" + blockKey + ".tpl"  [in modello "PseudoCode/pseudoBlocks.inc" in macro "printBlock" alla linea 122, colonna 20]
    - Raggiunto attraverso: Blocco @printBlock?children[0], shift [in modello "PseudoCode/pseudoBlocks.inc" in macro "printBlock" alla linea 107, colonna 9]
    ... (Aveva 18 più, nascosto per terseni) (Nascosto 4 “~” linee per tersità)

Come si aggiungono i modelli di codice per i rispettivi linguaggi di codice della strategia?

tomas262
Admin
Rispondi a  Matteo Nowlis
28. 2. 2022 1:53 pm

Si può invece provare a importare il pacchetto da questa pagina https://strategyquant.com/codebase/forceindex/

Lo pseudocodice e la MT4 sono stati implementati e funzionano quando sono stati testati.