Introduzione

Nel mondo del trading finanziario, la transizione da investitore discrezionale a trader sistematico rappresenta uno spartiacque fondamentale. Grazie a piattaforme come ProRealTime, oggi è possibile trasformare un’idea operativa in un algoritmo automatico capace di analizzare i mercati, generare segnali e testare strategie su anni di dati storici.

Se hai preso in mano questo libro, significa che hai già superato la fase iniziale. Ora, però, ti trovi di fronte a quel salto di qualità che separa chi si limita a usare la piattaforma da chi, invece, impara a padroneggiarla. Questo testo nasce esattamente per colmare questo spazio vuoto, posizionandosi un passo oltre i manuali introduttivi di base.

Nelle pagine che seguono esploreremo le strutture logiche intermedie del linguaggio di programmazione ProBuilder: dalla gestione avanzata della sintassi fino alla costruzione di indicatori personalizzati e sistemi di trading automatici.

Il focus del testo è fornire un metodo pratico per costruire trading system robusti, leggibili e facilmente modificabili. Affronteremo nel dettaglio la gestione delle condizioni operative, l’utilizzo efficiente delle variabili, l’ottimizzazione dei parametri, il risk management e l’analisi rigorosa delle prestazioni attraverso i backtest.

La programmazione finanziaria è un percorso che unisce logica, disciplina e creatività. Ogni codice nasce da un’intuizione, ma solo attraverso test rigorosi e una corretta implementazione può trasformarsi in uno strumento operativo efficace. Questo libro vuole accompagnarti proprio in questo percorso: dalla semplice regola di trading alla costruzione di strategie strutturate e professionali.

La programmazione è un’abilità che si acquisisce per tentativi ed errori. Abbandona l’idea del trading system miracoloso venduto su internet: la vera libertà operativa passa solo dalla tua capacità di scrivere, testare e validare le tue idee in totale autonomia.

Buona lettura e buon lavoro sui mercati!

Parte Prima: Le basi di ProRealTime

ProRealTime è un software professionale per l’analisi tecnica ed il trading online, utilizzato sia da trader principianti che esperti. ProRealTime è una piattaforma completa che consente di analizzare i mercati finanziari attraverso grafici ed indicatori tecnici avanzati.
Una delle sue caratteristiche distintive è la possibilità di programmare strategie di trading automatico: gli utenti possono creare, testare e ottimizzare sistemi basati su regole precise, che vengono poi eseguiti in modo automatico sui mercati.

Nel trading discrezionale il trader prende direttamente le decisioni operative, analizzando grafici, indicatori e contesto di mercato. Nel trading automatico, invece, le regole di ingresso e uscita vengono tradotte in un sistema che esegue le operazioni secondo criteri predefiniti.

Tra i principali punti di forza del trading sistematico ne elenchiamo tre:
– il primo è il rispetto della disciplina operativa, possibile attraverso l’eliminazione delle emozioni che sono una delle cause principali di errore nel trading
– il secondo punto di forza è la verifica della validità di un idea operativa, che può sembrare buona a livello intuitivo, ma che dopo dei test non si dimostra più tale
– il terzo punto di forza è la possibilità di operare 24 ore al giorno, ossia di sfruttare tutte le tendenze che un mercato può offrire, cosa non fattibile discrezionalmente.

Con questa guida intendiamo fornire le basi per conoscere le principali funzioni di programmazione di ProRealTime, affinché ciascuno possa iniziare a scrivere codici basati sulle proprie idee di trading e testarli per verificarne l’efficacia.

Capitolo 1: Le funzioni base sul tempo

Per orientarsi in un grafico finanziario servono delle coordinate. Si utilizzano due scale: quella orizzontale, l’asse delle ascisse, che rappresenta il tempo, e quella verticale, l’asse delle ordinate, che rappresenta il valore, cioè il prezzo dello strumento finanziario.

§ 1.1 – La funzione: barIndex

Partiamo dalla scala temporale, l’asse delle ascisse. Il contatore delle barre (o candele) di un grafico si chiama BARINDEX. BarIndex conta le barre da sinistra a destra, partendo dalla prima dello storico visualizzato. La prima barra caricata a sinistra rappresenta la barra numero 1. Se barIndex ha valore 1000 vuol dire che sono passate 1000 barre dall’inizio della strategia.

BarIndex è un numero progressivo e si utilizza con le parentesi quadre, per cui se in questo momento barIndex ha valore [2000] (ultima barra a destra del grafico), barIndex[1] ha valore 1999 e così via (barIndex[1] si può anche scrivere: barIndex-1).
Nell’esempio sopra per avere come riferimento l’ultima candela in assoluto in questo momento basta scrivere: close[BarIndex] ed è come scrivere: close[2000], ed alla candela successiva close[2001].

Vediamo un semplice esempio in cui utilizziamo barIndex per ignorare le prime cinque barre e il close viene restituito dalla sesta barra in poi:

In questo esempio più complesso utilizziamo barIndex per determinare la durata della validità di un ordine:

Se l’ordine limite non è eseguito, si può entrare con un ordine a mercato:

In quest’altro esempio usiamo barIndex (che, ripetiamo, è un contatore intero che possiamo utilizzare per fare confronti, filtri o calcoli sulla posizione della barra nel tempo) per eseguire azioni periodiche ogni numero N di barre (utilizziamo in questo esempio l’operatore MOD che ci restituisce il resto della divisione).
Apriamo in questo esempio posizioni ogni 10 barre se è presente il segnale crossover:

§ 1.2 – La funzione: intradayBarIndex

Per contare le barre intraday si usa la funzione INTRADAYBARINDEX.
Il contatore mostra il numero di barre a partire dall’inizio della giornata e rimette il valore a zero ad ogni nuovo inizio di giornata.
Questa funzione è molto utile nella programmazione in quanto permette di resettare dei valori all’inizio del giorno per poi verificare come questi si modificano nell’arco della giornata.

Con intradayBarIndex possiamo identificare in modo preciso la posizione di una barra (candela) all’interno della giornata di contrattazione, assegnando un numero progressivo ad ogni barra a partire dall’apertura del mercato.

Vediamo alcuni esempi didattici.
In questo esempio fissiamo il massimo ed il minimo della prima candela della giornata, ed entriamo al superamento di uno dei due:

In quest’altro esempio entriamo a mercato dopo che sono passate dieci candele:

Qui operiamo soltanto entro le prime sei barre della giornata se abbiamo una chiusura maggiore a quella precedente:

§ 1.3 – La funzione: tradeIndex

Abbiamo visto che barIndex ed intradayBarIndex sono funzioni che determinano in automatico rispettivamente il numero di barre generali ed intraday.
La funzione TRADEINDEX (che è ugualmente un contatore di barre sull’asse temporale delle ascisse) indica invece un punto temporale statico: la barra di apertura di un trade operativo.
TradeIndex si scrive con le parentesi rotonde. La barra dell’ordine aperto precedentemente si scrive: tradeIndex (1) (il primo ordine si trova spesso scritto anche senza numerazione come: tradeIndex).

TradeIndex in pratica è il numero della barra (sempre seguendo la progressione di barIndex), di quando un trade è iniziato. Quindi all’apertura di un trade barIndex e tradeIndex hanno lo stesso numero, ad esempio barra numero 1000, poi tradeIndex rimane invariato mentre barIndex viene costantemente incrementato.

Con tradeIndex (che troviamo usato spesso insieme a barIndex) passiamo quindi alla parte operativa del trading. Tramite l’espressione: (barIndex – tradeIndex), possiamo infatti sapere quante candele sono passate dall’inizio del trade.

Vediamo alcuni esempi.
In questo primo esempio chudiamo l’operazione se dopo 10 barre dall’entrata non si è formato un nuovo massimo.

Altro esempio in cui, dopo essere entrati a mercato, chiudiamo la posizione se è stata aperta da almeno 3 barre (in pratica dopo 3 barre dall’apertura):

Nei codici troviamo spesso questa formula usata per limitare la strataegia a una sola operazione al giorno. Si definisce la variabile “firstBar” che calcola l’indice della prima barra della giornata. TradeIndex(1) invece come abbiamo visto restituisce l’indice della barra dell’ultimo trade chiuso/aperto.
Se l’ultimo trade è avvenuto prima dell’inizio della sessione attuale, allora notTraded = 1, se è avvenuto dopo l’inizio della sessione invece: notTraded = 0.

Possiamo usare tradeIndex anche per incrementare una posizione ogni 5 giorni. Verifichiamo che tradeIndex sia divisibile per 5 (quindi quando la divisione per 5 darà come resto ZERO in modo che non dobbiamo fare calcoli delle barre):

Abbiamo visto che tradIndex(1) segna sull’asse temporale l’ultimo trade e si usa spesso come indice di apertura di una posizione.
Un costante specifica per la chiusura di un trade non c’è, ma la possiamo creare in questo modo e la chiamiamo, per esempio, closeIndex:

Questa espressione è molto utile nella pratica in quanto ci permette di sapere da quante barre l’ultimo trade è stato chiuso.
In questo esempio di un trading system rientriamo in posizione dopo una precedente chiusura se permane lo stesso segnale.

Capitolo 2: Le funzioni sul prezzo

Dopo aver visto le principali funzioni per orientarsi nell’asse temporale di un grafico, passiamo al prezzo.
Quando parliamo genericamente di prezzo, ci riferiamo alla chiusura. In ProRealTime, infatti, i segnali vengono generati alla chiusura della barra e, normalmente, l’ordine viene eseguito all’apertura della barra successiva, secondo le regole di esecuzione della strategia.

In una barra distinguiamo: Open, High, Low e Close. ProRealTime fornisce anche delle utili costanti derivate dai prezzi che sono:

§ 2.1 – La funzione: tradePrice

Il comando TRADEPRICE(n) si utilizza con le parentesi rotonde e permette di trovare il prezzo della transazione precedentemente eseguita. Se non è specificato tradePrice equivale all’ultimo ordine eseguito, ossia tradePrice(1). TradePrice(2) è invece il trade precedente e così via.

La funzione tradePrice in ProRealTime serve per recuperare il prezzo di esecuzione di un trade. È molto utile per costruire logiche su stop, target o gestione della posizione basate sul prezzo reale di ingresso.

Occorre fare attenzione ad una cosa: tradePrice(1) non è il prezzo di entrata, ma semplicemente l’ultimo prezzo tradato. Dobbiamo distinguere due casi per fare chiarezza. Se siamo dentro una posizione, tradePrice(1) corrisponde al prezzo di apertura del trade. Se invece non siamo a mercato, tradePrice(1) è il prezzo di uscita dal trade: è cioè il prezzo dell’ultima posizione chiusa. In questo caso se vogliamo sapere il prezzo di entrata dobbiamo scrivere tradePrice(2).

Ecco un esempio di utiilizzo di tradePrice(1): usciamo da una posizione quando si guadagna il 5% rispetto al trade precedente:

Qui usciamo quando abbiamo raggiunto come target 10 punti sopra il prezzo di entrata:

In questo esempio utilizziamo tradePrice(1) per creare uno stop loss in una posizione long:

Per riassumere: tradeIndex ci dice quando abbiamo eseguito il trade (numero di barra), mentre tradePrice ci dice a che prezzo lo abbiamo eseguito.

§ 2.2 – La funzione: positionPrice

Il comando POSITIONPRICE permette di conoscere il prezzo medio di acquisto della posizione aperta in corso. A differenza di tradePrice(1) che restituisce il prezzo dell’ultimo singolo trade, positionPrice riflette la media ponderata di tutti i contratti aperti.
PositionPrice viene calcolato come la somma di tutti i prezzi di entrata ponderati dalla quantità di ogni ordine. Se si aggiunge una posizione cambierà quindi il valore di positionPrice.

L’istruzione positionPrice si utilizza con le parentesi quadre, come strategyProfit. PositionPrice[1] restituisce il valore della posizione alla chiusura della barra precedente.

Un esempio: se si acquista un’azione a 5$, poi un’altra a 10$ ed infine un’altra a 15$, il valore di positionPrice sarà di 10$: (5+10+15)/3.
Se si aggiungono posizioni la media verrà chiaramente ricalcolata, mentre se si vende una parte della posizione (ad esempio una delle tre azioni acquistate nell”esempio), positionPrice non cambierà e sarà sempre 10$.

In questo esempio apriamo una seconda posizione se il prezzo scende più di 20 punti dall’ultimo trade, sono passate almeno 5 barre e abbiamo meno di due posizioni aperte. Usciamo quando il prezzo risale sopra il prezzo medio e si hanno almeno due contratti aperti:

Chiaramente con una sola posizione aperta positionPrice (prezzo medio della posizione) è identico a tradePrice (prezzo dell’ultimo trade) e si possono usare indistintamente.

§ 2.3 – La funzione: positionPerf

Il comando POSITIONPERF(n), vuole le parentesi rotonde e restituisce la performance di una posizione aperta in percentuale sul prezzo (commissioni non incluse).
PositionPerf, ad esempio, può restituire 0.01 se la performance è positiva oppure -0.07 se la performance è negativa.
In pratica fornisce la performance attuale se n = 0, oppure la performance dell’ennesima ultima posizione chiusa se n > 0 .

Positionperf è quindi il moltiplicatore diviso 100 (100% = 1): 0.3% è uguale a 0.003, positivo se in guadagno e negativo se in perdita.
In generale positionPerf può servire quindi sia a conoscere:
– il risultato di un’operazione in corso,
– l’esito di operazioni chiuse.

Ecco un esempio di utilizzo di positionPerf (con operazione aperta) in cui si chiude un trade se stiamo guadagnando più del 2%.
E’ importante ricordare che positionPerf varia ad ogni candela, in quanto si aggiorna costantemente con la formazione della candela.

In questo esempio usciamo da un trade quando stiamo guadagnando più del 2%.

Ecco un esempio di utilizzo di positionPerf (questa volta con operazioni già chiuse) in cui apriamo un nuovo trade se il trade precedente ha guadagnato almeno il 10%:

PositionPerf può quindi servire a conoscere in generale se il trade precedente è stato chiuso in profitto: positionPerf(1) > 0, oppure in perdita: positionPerf(1) < 0.

In questo esempio modifichiamo lo stop loss se ci sono stati due trade in perdita consecutivi:

Utilizziamo in questo ultimo esempio positionPerf e barIndex per ritardare nuovi ingressi di un certo numero di barre dopo un operazione in perdita.

§ 2.4 – La funzione: strategyProfit

L’istruzione STRATEGYPROFIT restituisce i guadagni o le perdite assolute, nella valuta dello strumento utilizzato (commissioni escluse) realizzate dall’inizio del sistema di trading.
StrategyProfit restituisce il risultato complessivo della strategia, aggiornato all’ultima posizione chiusa.
Si può usare con l’istruzione “quit” (che vedremo meglio più avanti) per interrompere un sistema di trading quando questo eccede determinate perdite.

Occorre ricordare che i sistemi di trading sono valutati alla chiusura della barra. Nell’esempio sopra riportato quindi le perdite possono anche essere superiori al valore stabilito nel caso di una grossa perdita in una singola candela o nel caso di un gap. Quindi prima di usare questo codice è necessario impostare degli stop loss per una maggiore protezione.

Questa istruzione si utilizza con le parentesi quadre: strategyprofit[1] dà il profitto/perdita alla chiusura del trade precedente.
StrategyProfit quindi è il risultato, aggiornato all’ultima operazione chiusa, del TOTALE dei profitti/perdite di un sistema e si usa principalmente per sapere quanto una strategia ha guadagnato complessivamente fino a quel momento.
Tuttavia si può anche utilizzare per verificare se l’ultima operazione chiusa è stata profittevole: strategyProfit > strategyProfit[1] oppure perdente: strategyProfit < strategyProfit[1].

Ecco un esempio in cui interrompiamo l’operatività se abbiamo più di due perdite:

Ricordiamo che per sapere se l’ultima operazione era stata positiva si poteva anche usare positionPerf(1) > 0. PositionPerf(0) infatti è la posizione in tempo reale, mentre strategyProfit non si usa per il tempo reale.
Spesso, come vedremo, si usano insieme queste due istruzioni per determinati scopi.

Da ricordare: strategyProfit viene aggiornato solo alla CHIUSURA di un operazione.
Se un’operazione ha prodotto risultato 0, allora strategyProfit è uguale a strategyProfit[1].
A questo punto si possono verificare varie condizioni, che sono utili nella costruzione di codici:

Una formula del moderatore italiano del forum di ProRealCode, Roberto Gozzi, che riportiamo in quanto si usa spesso in vari codici operativi per verificare che ci sia stata una operazione anche aperta e chiusa sulla stessa barra è la seguente:

In pratica verifica che STRATEGYPROFIT sia identica, che non fosse a mercato prima, né dopo (quindi una sola barra), che l’operazione si sia davvero chiusa la barra precedente e che si sia anche aperta nella stessa barra, tramite TRADEINDEX.

Un utilizzo molto importante di strategyProfit è quello che consente di salvare il profitto/perdita di un trading system. Qui salviamo il profitto all’inizio di ogni mese per limitare la massima perdita mensile di un sistema.

Possiamo anche immagazzinare strategyprofit in una variabile per calcolare il profitto giornaliero della strategia per sapere quanto si è guadagnato/perso dall’inizio della giornata:

Per riassumere le differenze ed il principale utilizzo tra queste due fondamentali funzioni:
– strategyProfit restituisce il totale progressivo delle operazioni chiuse e permette di conoscere lo storico della strategia
– positionPerf restituisce la percentuale di guadagno o perdita (se è un valore negativo) dell’operazione aperta.

Alla chiusura di un’operazione strategyProfit viene aggiornato e positionPerf viene azzerato. Quando si apre una nuova posizione strategyProfit rimane invariato come era prima mentre positionPerf viene aggiornato candela per candela.

§ 2.5 – Come controllare la posizione in tempo reale

StrategyProfit rappresenta il risultato, aggiornato all’ultima operazione chiusa, del totale dei profitti/perdite di ogni operazione della strategia.
Per conoscere il profitto attuale (ad ogni barra) dobbiamo aggiungere positionPerf.

Nello specifico, per conoscere i PUNTI per singola posizione o totali usiamo questa formula:

Per conoscere il GUADAGNO aggiornato alla candela corrente, per singola posizione o totale, usiamo:

Vediamo questo esempio in cui si lega una condizione monetaria ad un indicatore per uscire da una posizione:

Da notare che strategyProfit (profitto all’ultima operazione chiusa) più positionPerf*positionPrice / pointSize *pointValue (profitto temporaneo globale) rappresenta la curva dei guadagni e delle perdite della strategia.

Possiamo quindi inserire questa curva in una variabile e applicarci degli indicatori, come una media, per analizzare l’andamento della strategia.

Un altro modo per sapere quanto sta guadagnando in punti un TS dopo un certo numero di barre è il seguente (calcola il profit/loss corrente in punti della posizione aperta):

§ 2.6 – La funzione: countOfPosition

In ProRealTime abbiamo 3 variabili che permettono di verificare lo stato della nostra posizione:
– onMarket: vale 1 se abbiamo delle posizioni aperte altrimenti 0
– longOnMarket: vale 1 se abbiamo delle posizioni lunghe aperte altrimenti 0
– shortOnMarket: vale 1 se abbiamo delle posizioni corte aperte altrimenti 0

Per contare queste posizioni durante il trading operativo utilizziamol’istruzione COUNTOFPOSITION, che è un contatore di posizioni.
Se siamo long countOfPosition sarà = 1, se siamo short di un contratto countOfPosition sarà: -1. Se abbiamo due ingressi long countOfPosition sarà uguale a 2.

Se non utilizziamo strategie con posizioni cumulate (in cui vogliamo controllare il numero dei contratti) per sapere se, ad esempio, non siamo a mercato (ossia non abbiamo posizioni aperte) possiamo scrivere sia: not onMarket, che countOfPosition = 0. Se invece siamo a mercato, possiamo scrivere sia: onMarket che countOfPosition = 1.

§ 2.7 – La funzione: countOfLong/ShortShares

CountOfPosition è un contatore generale. Con COUNTOFLONGSHARES e COUNT OF SHORTSHARES possiamo invece riferirci specificatamente a posizioni aperte lunghe o corte.
Questo contatore si usa spesso con posizioni cumulate.
Ecco un esempio in cui si entra al cross del macd e poi si incrementa la posizione se il prezzo continua a salire limitando l’accumulo di nuove posizioni ad un massimo prefissato.

In questo esempio invece si utilizza la funzione countOfShortShares per evitare lo stop&reverse di un trading system trend following in cui long e short hanno segnali indipendenti per cui le posizioni si potrebbero invertire senza attendere la chiusura naturale della posizione (spesso basta usare: “not onMarket” per evitare lo stop and reverse).

Il codice sopra riportato permette nuove entrate solo se siamo flat, ecco perché basterebbe usare: not onMarket.
Se invece vogliamo chiudere prima una posizione e poi aprirne una di segno opposto in cui non passiamo da short a long nella stessa barra, ma prima chiudiamo lo short e poi entriamo long se il segnale buy è ancora valido, allora usiamo questa scrittura:

Capitolo 3: Funzioni avanzate

Dopo aver visto le istruzioni base di ProRealTime, il passo successivo è usare strumenti più “potenti” con cui poter analizzare il comportamento di un insieme di barre.
Le funzioni iterative permettono questo: ripetono un calcolo su più barre, sia implicitamente con SUMMATION (ProRealTime gestisce il ciclo internamente e noi vediamo solo il risultato), sia esplicitamente con FOR (decidiamo noi il numero di iteraziioni e cosa fare).

§ 3.1 – La funzione: summation

SUMMATION (somma totale) è una funzione abbastanza utilizzata che si usa per sommare un insieme di valori in un certo periodo temporale, ossia un determinato numero di barre. Nelle parentesi quadre si inserisce il numero di candele da sommare e nelle parentesi rotonde cosa si vuole sommare.

Un semplice esempio chiarisce meglio le cose: ecco come possiamo sommare i volumi delle ultime 10 candele:

In questo esempio controlliamo quante delle ultime quattro barre hanno avuto una chiusura positiva:

Un utilizzo interessante è usare summation per vedere se si è verificata una determinata condizione negli ultimi periodi. Possiamo ad esempio verificare se almeno una volta ( > 0), nelle ultime 10 candele, c’è stato il cross del prezzo su una determinata media:

Oppure possiamo verificare se ci sono state cinque candele consecutive di prezzo sopra una determinata media:

In quest’altro esempio usiamo summation per evitare che ci sia stato un cross di un indicatore in un numero precedente di barre (con [1] partiamo dalla barra precedente al cross):

Oppure con summation possiamo creare delle condizioni da inserire in un TS.
In questo esempio utilizziamo summation per definire due scenari di mercato che diventano delle condizioni da inserire in un sistema.

Qui cerchiamo una zona del grafico in cui abbiamo le ultime dieci barre sopra una media, mentre le precedenti dieci barre erano sotto questa media:

Quindi il segnale long scatta solo se:
– da 20 a 11 barre fa abbiamo 10 barre consecutive sotto la media
– da 10 barre fa ad oggi abbiamo 10 barre consecutive sopra la media

Se vogliamo delle condizioni meno restrittive in cui oggi siamo sopra la media, mentre prima del cross eravamo sotto la media per 10 candele:

Questo codice in ProRealTime usa summation per cercare un pattern specifico: 3 candele verdi consecutive seguite da una candela rossa (la candela attuale è ribassista):

Vediamo infine un esempio di come si costruisce con summation l’uscita di un trading system con l’oscillatore bPercent: usciamo quando in due delle ultime quattro barre l’indicatore è sotto un certo livello.

§ 3.2 – I cicli FOR

Il ciclo FOR è una delle funzioni avanzate del linguaggio ProBuilder di ProRealTime. Permette di ripetere un blocco di istruzioni un numero definito di volte, scorrendo un intervallo di valori.

L’istruzione FOR è utilizzata quando si desidera richiamare uno per uno una serie finita di elementi. Questa è la sintassi di base:

Il ciclo più semplice: somma i valori di chiusura delle ultime n barre e li accumula in una variabile.

Qui contiamo quante delle ultime n barre sono rialziste (chiusura > apertura) e quante ribassiste. Ottimo punto di partenza per capire come usare IF dentro un FOR.

Possiamo identificare il numero di barre tra un massimo ed un minimo all’interno di un range:

Possiamo ad esempio cercare la candela con il range più grande di un determinato periodo per filtrare il mercato. Qui entriamo a mercato quando la candela corrente ha un range maggiore di tutti i 20 range precedenti:

Molte volte possiamo anche evitare il loop e possiamo scrivere:

Possiamo contare, per crearci ad esempio una condizione da inserire in un sistema, il numero di barre rialziste di un periodo. Questo codice conta quante candele rialziste ci sono nelle ultime 100 barre

Quando cerchiamo di uscire da una istruzione FOR senza arrivare all’ultimo valore utilizziamo BREAK. Ecco un esempio che somma il numero dei rialzi consecutivi delle ultime 20 barre fermandosi in caso di massimi inferiori:

Bisogna ricordare infine che ogni barra riesegue tutto il loop. Per questo è consigliato di utlizzare l’istruzione FOR con moderazione per non eseguire un numero troppo elevato di calcoli.

§ 3.3 – Le funzioni: MIN – MAX

Le funzioni MIN e MAX sono fondamentali per analizzare il comportamento del prezzo: servono a individuare rispettivamente il valore minimo e massimo all’interno di determinati valori.

La differenza principale con highest[n] e lowest[n], è che queste funzioni guardano tutte le ultime n barre di una serie storica, mentre max(a, b) e min(a, b) confrontano soltanto i valori specifici che gli passiamo.

Vediamo la differenza con highest che invece ricerca un valore in un range:

Un utilizzo molto frequente di min/max è quello di confrontare più valori contemporaneamente.
In questo esempio usiamo questa funzione per scegliere lo stop loss dinamico, posto inizialmente sul minimo e poi aggiornato a minimi crescenti (snippet 317):

Un altro utilizzo interessante è quello che ci consente di scegliere uno stop loss tra il più distante di due valori:

Un ulteriore utilizzo che segnaliamo è quello per costruire dei pattern.
Qui definiamo la figura dell’Hammer nell’analisi candlestick:

Capitolo 4: Istruzioni di controllo

Vediamo ora altre funzioni importanti che si usano nella programmazione di trading system, ossia le istruzioni di controllo: ONCE e QUIT. Queste controllano come e quando il codice viene eseguito, senza fare calcoli.

§ 4.1 – La funzione ONCE

L’istruzione ONCE è un’istruzione di inizializzazione, è una direttiva di quando eseguire il codice: serve a dichiarare una variabile “una sola volta”.
Il linguaggio proBuilder legge il codice per un numero di volte pari al numero di barre presenti sul grafico. Con “ONCE” invece leggiamo il codice soltanto la prima volta, in quanto, in caso di rilettura del codice da parte del linguaggio, saranno conservati i valori calcolati durante la lettura precedente.

Vediamo un esempio con un contatore progressivo:

Esaminiamo cosa succede in questo codice:
– prima barra → count = 0
– poi diventa 1
– seconda barra → diventa 2
– terza barra → diventa 3 …
Senza ONCE, il contatore si resetterebbe sempre.

Quasi sempre once si usa per inizializzare una variabile (con valore iniziale = 0) e poi assegnargli il valore in seguito. In questo esempio si memorizza il prezzo di chiusura della prima barra che rompe il massimo delle 20 barre precedenti (solo il primo breakout finché non si resetta entryPrice):

Un esempio molto didattico è inizializzare il capitale iniziale di una strategia e poi calcolare l’equity corrente (senza once capital verrebbe sempre riassegnato a 10000 ad ogni barra). Invece con once capital = 10000 viene memorizzato solo all’inizio e poi cambia solo strategyProfit.

§ 4.2 – La funzione QUIT

QUIT è un controllo di flusso, interrompe l’esecuzione del codice sulla barra corrente.
Con la funzione QUIT possiamo bloccare in qualsiasi momento una strategia per differenti ragioni. Una motivazione può essere temporale:

Oppure per motivazioni monetarie:

Capitolo 5: Il concetto di flag

In ProRealCode (il linguaggio di programmazione di ProRealTime), un flag è semplicemente una variabile che funziona come un interruttore: vale 0 (spento/falso) oppure 1 (acceso/vero).
Un flag permette di ricordare se una certa condizione si è verificata e di condizionare il comportamento del codice nelle barre successive.
Di solito viene utilizzato così:
flag = 0 → la condizione non è attiva / l’evento non è ancora avvenuto
flag = 1 → la condizione è attiva / l’evento è avvenuto
In pratica, il flag permette alla strategia di “ricordare” che qualcosa è successo e di utilizzare questa informazione per decidere cosa fare nelle barre successive.

In questo esempio didattico di flag, vengono mostrate chiaramente le tre fasi: inizializzazione → attivazione → utilizzo → reset.

§ 5.1 – Flag binario

La forma più comune dei flag è quella binaria, con cui attiviamo o meno determinati comportamenti in base a determinate condizioni.
In questo esempio attiviamo il flagLong se l’indicatore RSI supera al rialzo la soglia dei 50.

I flag sono il fondamento di qualsiasi strategia complessa in ProRealCode: gestione degli ordini, filtri anti-ripetizione, trailing stop condizionali ed altro. Padroneggiarli significa poter costruire sistemi di trading robusti e controllabili barra per barra.

Vediamo alcuni modi equivalenti di scrivere un codice.
Nel primo esempio memorizziamo il prezzo di un breakout (myBuy) mentre nel secondo esempo per ricordare il breakout utilizziamo un flag (cExit = 1).

Oppure possiamo scrivere il codice con un flag utilizzando valori booleani:

In questo esempio tratto da un trading system usiamo dei flag binari per verificare se la distanza tra il massimo raggiunto nelle ore notturne e la chiusura di ieri è maggiore di un determinato livello.

§ 5.2 – Flag contatore

Un flag contatore è una variabile numerica che non si limita a dire “sì/no” come un flag binario, ma conta quante barre sono trascorse da quando si è verificato un evento: è lo strumento fondamentale ogni volta che il tempo, misurato come numero di barre, diventa parte della logica di trading.

Il flag binario risponde alla domanda: “è successo qualcosa?”.
Il flag contatore risponde a domande più complesse come:
– “Quante barre fa è avvenuto il segnale?”
– “Siamo ancora dentro la finestra temporale valida?”
– “Dopo quante barre devo uscire dalla posizione?”
– “Il pattern deve completarsi entro n candele?”

Senza un contatore, ProRealCode non ha modo di misurare il tempo trascorso tra due eventi: ogni barra ricomincia da zero e non ricorda nulla di ciò che è venuto prima.

Vediamo ora tre utilizzi pratici del flag contatore:

– Uscita a tempo: entriamo a mercato e vogliamo uscire automaticamente dopo un numero fisso di candele, indipendentemente dal prezzo.
Il flag memorizza uno stato e barreLong misura quante barre sono trascorse.

– Finestra di conferma entro n barre: dato un segnale, aspettiamo che un secondo segnale arrivi entro una finestra temporale. Se non arriva in tempo, il primo segnale decade. In questo esempio un flag mantiene in memoria un primo segnale in attesa di una conferma, con una finestra temporale di 5 barre.

– Blocco dopo un segnale: dopo un segnale, impediamo che il sistema generi nuovi ordini per n barre. Essenziale per evitare di rientrare immediato dopo uno stop.

Un errore da evitare quando si usa il flag è dimenticare di azzerare il contatore al reset della flag.

Come abbiamo visto i flag sono fondamentali quando si inizia a scrivere del codice minimamente più avanzati del livello base.
Un consiglio per rendere più chiaro il codice è di dare al flag un nome che ricordi la funzione per il quale si utilizza.

Capitolo 6: Date e tempo in PRT

ProRealTime mette a disposizione un ricco insieme di funzioni per lavorare con date e orari direttamente nel codice ProBuilder. Queste funzioni sono fondamentali per costruire strategie che rispettino le sessioni di mercato, filtrino per giorno della settimana, o reagiscano a momenti specifici del calendario.

Le categorie principali sono:

Date — Le funzioni Year, Month e Day restituiscono il componente della data della barra corrente. Ad esempio Month = 12 è vero solo per le barre di dicembre.

Giorno della settimana/anno — DayOfWeek restituisce un numero da 1 (lunedì) a 7 (domenica), permettendo di escludere facilmente certi giorni dalla strategia. DayOfYear conta i giorni dall’inizio dell’anno.

Time — Hour, Minute e Second restituiscono l’ora della barra. Sono indispensabili per delimitare le sessioni operative: apertura europea, americana …

§ 6.1 – La funzione: Date

In ProRealTime la funzione DATE permette di identificare la data della barra corrente durante l’esecuzione di un indicatore o di una strategia automatica.
La funzione DATE è molto utile quando vogliamo far eseguire una strategia solo in determinati giorni o periodi temporali. Può essere usata per diversi scopi come:
– attivare/disattivare strategie in date specifiche
– escludere determinati giorni
– effettuare backtest su intervalli precisi
– creare logiche legate a eventi temporali

La funzione DATE restituisce la data della barra corrente nel seguent formato: YYYYMMJJ (anno, mese, giorno). In ProRealTime DATE indica la data di chiusura della candela, cioè il momento in cui la candela si “chiude” formalmente.

Possiamo usare DATE per filtrare un sistema da un certo perido:

OPENDATE restituisce la data di apertura della barra, anch’essa nel formato YYYYMMJJ.

La distinzione diventa rilevante su timeframe multiday o settimanali/mensili: una barra settimanale, ad esempio, apre di lunedì e chiude di venerdì. OPENDATE restituisce il lunedì, DATE restituisce il venerdì.
Sul daily e intraday sono intercambiabili, su weekly/monthly fanno la differenza.
Su weekly, OPENDATE restituisce il lunedì di apertura e DATE il venerdì di chiusura. Su monthly, OPENDATE restituisce il primo giorno lavorativo del mese, mentre DATE è tecnicamente la data di chiusura della barra

§ 6.2 – La funzione: DayOfWeek

DAYOFWEEK restituisce il giorno della settimana relativo alla data di chiusura della barra.
Si parte da domenica = 0, lunedi = 1, martedi = 2, mercoledi = 3 ….

Vediamo alcuni esempi. Qui operiamo il lunedi:

In ProRealTime DAYOFWEEK restituisce il numero del giorno della settimana relativo alla data corrente della barra, mentre OPENDAYOFWEEK invece restituisce il giorno della settimana relativo alla data di apertura della barra (stessa logica della coppia DATE/OPENDATE, applicata al giorno della settimana).

In questo esempio si opera dal lunedi al venerdi.

Interessante anche l’utilizzo di dayOfWeek per evitare di operare in determinati giorni della settima. Se, ad esempio, un backtest di un trading system ci dice di non operare il venerdi allora inseriamo questo codice:

Su compressione settimanale DAYOFWEEK restituisce sempre 5 (venerdì) e OPENDAYOFWEEK restituisce sempre 1 (lunedì) — quindi su quel timeframe sono di fatto costanti e poco utili singolarmente.

Su timeframe intraday brevi, ad esempio 1 minuto, OPENDAYOFWEEK e DAYOFWEEK coincidono nella maggior parte dei casi, perché apertura e chiusura della candela cadono nello stesso giorno.
Se vuoi agire in corrispondenza dell’apertura di una sessione, ad esempio entrare solo all’apertura del mercato del martedì, usa OPENDAYOFWEEK insieme a un controllo sull’orario, ad esempio TIME.
Se invece vuoi associare una regola al giorno di chiusura della candela, usa DAYOFWEEK; questa distinzione è rilevante soprattutto per candele che attraversano la mezzanotte. Per una condizione basata sul giorno corrente in tempo reale, indipendente dalla candela, usa CURRENTDAYOFWEEK.

§ 6.3 – La funzione: Time

In ProRealTime, TIME e OPENTIME sono costanti temporali per strategie e indicatori, ma si riferiscono a momenti diversi della barra corrente.

TIME restituisce l’orario di chiusura della barra nel formato HHMMSS.
OPENTIME restituisce l’orario di apertura della barra corrente, anche esso nel formato HHMMSS (es. 093000 per 09:30:00). Non indica il momento in cui il sistema è entrato a mercato, ma l’inizio temporale della candela.

Su un grafico a 1 ora, la candela che apre alle 16:00:00 ha OPENTIME = 160000 e chiude alle 17:00:00, quindi ha TIME = 170000. Di conseguenza, OPENTIME = 170000 precede temporalmente TIME = 170000 di un’ora.

Se scrivi OPENTIME = 170000, identifichi l’inizio della candela delle 17:00. Se scrivi TIME = 170000, identifichi la candela che chiude alle 17:00, quindi quella aperta alle 16:00. In pratica, su grafico orario, TIME = 170000 è associato alla chiusura della candela 16:00–17:00.

Ecco un esempio dove chiudiamo tutte le posizioni dopo le 17:30:

Spesso usiamo time per definire delle fascie di tempo in cui operare, ecco un esempio:

Possiamo anche fissare il massimo ed il minimo in una certa ora:

In questo esempio compriamo all’inizio di una candela orario ed usciamo all’inizio di un altra candela oraria.

§ 6.4 – La funzione DCLOSE

In ProRealTime le funzioni giornaliere come DClose, DHigh, DLow e DOpen permettono di richiamare i dati del timeframe daily anche se stiamo lavorando su grafici intraday (es. 5 minuti, 15 minuti, 1 ora).
Queste funzioni sono molto utili in quanto consentono di integrare informazioni della giornata corrente o precedente all’interno di strategie intraday.

– DClose(n) è la chiusura giornaliera
– DHigh(n) è il massimo giornaliero
– DLow(n) è il minimo giornaliero
– DOpen(n) è l’ apertura giornaliera

Queste quattro funzioni restituiscono i dati della sessione giornaliera (daily), indipendentemente dal timeframe del grafico su cui si sta lavorando.
In particolare sono importanti quando si opera su grafici intraday ma si ha bisogno di fare riferimento ai valori del giorno.

– DHIGH e DLOW si aggiornano in tempo reale man mano che il prezzo si muove.
- DCLOSE durante la seduta corrente coincide con il prezzo corrente (close dell’ultima barra).
- DOPEN rimane fisso per tutta la seduta.

Nel seguente esempio compriamo quando oggi abbiamo una chiusura più alta del massimo di ieri.

In ProRealTime DHigh(0) rappresenta il massimo del giorno corrente aggiornato in tempo reale. Quindi se durante la giornata viene fatto un nuovo massimo, DHigh(0) cambia immediatamente, DHigh(1) invece è fisso.

Ricordiamo che con i CFD la chiusura non è alle 17:30, ma spesso è all’una di notte.
In ogni caso possiamo scegliere quando deve terminare la giornata con Dclose e per farlo possiamo utilizzare questo utile codice del moderatore dl forum di ProRealCode Ivan Gonzales che si trova nel forum inglese di ProRealTime.

§ 6.5 – Chiusure giornaliere

Abbiamo visto che è molto importante nella costruzione di sistemi riferirsi alla chiusura di giorni precedenti. Questo lo possiamo fare come visto con la funzione DClose, ma anche in altri modi.

Per riferirci al close di ieri potremmo anche scrivere: close = 173000, ma questo solo se oggi non sono ancora le 17:30, altrimenti, se sono ad esempio le 18:00 ci riferiremmo alla chiusura di oggi.

Quindi per avere sempre il close di ieri usiamo questo codice:

Entrata al superamento del massimo di tre giorni fa:

Con la stessa logica ci possiamo riferire a massimi e minimi di una determinata fascia temporale di ieri:

§ 6.6 – Chiusura settimanale e mensile

Oltre alle chiusure dei precedenti giorni, è utile anche potersi riferire a quelle settimanali e mensili.

In questo modo ci riferiamo invece alle chiusure settimanali:

Entrata con massimo superiore a quello di due settimane fa:

Entrata con massimo superiore a quello di 4 settimane fa:

In questo modo ci riferiamo invece alle chiusure mensili:

Cosi entriamo se abbiamo un massimo superiore a quello del mese precedente:

Capitolo 7: MultiTimeframe

Un modo ulteriore e più semplice di riferirsi ai dati passati è usare la funzione che ci mette a dispozione proRealTime che si chiama multiTimeFrame (MTF).
Con questa funzione possiamo:
– utilizzare contemporaneamente dati che provengono da diversi orizzonti temporali
– riferirci ai dati passati

La multitimeframe analysis in ProRealTime serve a usare più timeframe nello stesso sistema o indicatore. Un esempio: trend principale su timeframe ad 1 ora, ingresso sul timeframe a 5 minuti.

Il Multi-Timeframe trading (MFT) infatti è una metodologia che prevede l’analisi dello stesso strumento su più orizzonti temporali contemporaneamente, con l’obiettivo di aumentare la precisione delle operazioni filtrando i segnali in base al contesto più ampio.
Il principio di base è l’approccio top-down: dal timeframe superiore a quello inferiore.

L’idea fondamentale è semplice: il trend di un timeframe superiore ha la priorità:

Timeframe superiore (es. Daily): si stabilisce il contesto di mercato, siamo in tendenza rialzista, ribassista o in laterale? Si identificano i livelli chiave (supporti, resistenze, massimi/minimi significativi).

Timeframe intermedio (es. 4H -1H): si osserva la struttura di prezzo. Il movimento attuale è un ritracciamento del trend principale o un’inversione? Si individuano le zone di interesse per un possibile ingresso.

Timeframe inferiore (operativo, es. 15min – 5min): si cerca il segnale concreto di ingresso in accordo con i due livelli superiori, definendo stop loss e target in modo preciso.

Il MTF riduce significativamente i falsi segnali e migliora il rapporto rischio/rendimento perché si opera solo quando più timeframe convergono.
Un punto che potrebbe risultare problematico è che più livelli si consultano, più si rischia di trovare sempre una ragione per non entrare. Per ovviare a questo occorre definire regole chiare e gerarchiche prima di operare.

Attraverso la funzione multitimeframe (MTF) in ProRealTime possiamo combinare indicatori su timeframe diversi nello stesso grafico o strategia, migliorando la precisione dei segnali.

Nel timeframe superiore spesso si usa la funzione “updateonclose”
che permette di attendere la chiusura della barra superiore, evitando segnali instabili che si possono generare durante la formazione della candela.
Nel timeframe inferiore invece si indica il il tempo che si utilizza a livello operativo, oppure si scrive: “default”.

§ 7.1 – Trading MultiTimeFrame

Un utilizzo frequente del multitimeframe è quello di utilizzare i dati della giornata come riferimento generale ed i dati di un timeframe intraday per l’operatività (di solito si utilizzano due o tre orizzonti temporali), oppure due timeframe giornalieri abbastanza differenti.

Abbiamo detto che con il MTF possiamo riferirci con facilità ai dati passati.
Vediamo un esempio in cui compriamo se abbiamo un massimo superiore a quello della settimana scorsa:

Occorre fare attenzione che scriviamo massimo e minimo della settimana scorsa senza [1] solo perchè usiamo updateonclose, altrimenti sarebbe sbagliato.
Con updateonclose il timeframe superiore viene aggiornato solo quando la barra di quel timeframe si chiude. Per questo, la barra corrente [0] rappresenta l’ultima barra chiusa, mentre [1] rappresenta quella precedente.

Senza UPDATEONCLOSE, la barra [0] è la settimana corrente, cioè quella ancora in formazione.

Se vogliamo conoscere la chiusura dell’altro ieri con updateOnClose:

In sintesi:
– con updateOnClose: [0] è l’ultima settimana chiusa e [1] è la settimana precedente già chiusa,
– senza updateOnClose [0] è la settimana corrente, ancora in formazione e [1] è la settimana precedente, già chiusa.

Prendiamo un esempio intraday e supponiamo di avere un grafico a 15 minuti di default e di voler utilizzare i dati del timeframe orario.

1. Senza UPDATEONCLOSE [0] rappresenta la barra oraria corrente, che è ancora in formazione. Supponiamo che siano le 10:30. La situazione sarà:
barra oraria 10:00–11:00 → [0], ancora in formazione,
barra oraria 09:00–10:00 → [1], già chiusa,
barra oraria 08:00–09:00 → [2], già chiusa.
Quindi high[0] è il massimo della barra 10:00–11:00, ancora in formazione, mentre:
high[1] è il massimo della barra 09:00–10:00, già chiusa.

2. Con UPDATEONCLOSE il timeframe orario viene aggiornato solo quando la barra oraria si chiude.
Supponiamo sempre che siano le 10:30. La barra 10:00–11:00 è ancora in formazione, quindi non viene ancora considerata come nuova barra disponibile dal timeframe orario. Di conseguenza:
ultima barra oraria chiusa → 09:00–10:00 → [0]
barra oraria precedente → 08:00–09:00 → [1]
barra precedente ancora → 07:00–08:00 → [2]
Quindi high[0] è il massimo dell’ultima barra oraria chiusa, cioè 09:00–10:00 mentre high[1] è il massimo della barra oraria precedente, cioè 08:00–09:00.

In pratica [0] indica sempre la barra corrente del timeframe che stiamo utilizzando.
La differenza è quale barra viene considerata corrente:
senza UPDATEONCLOSE → [0] è la barra ancora in formazione;
con UPDATEONCLOSE → [0] è l’ultima barra chiusa disponibile.

Se vogliamo ad esempio comprare un minimo daily di ieri utilizzando un timeframe operativo a 15 minuti scriviamo:

Vediamo ora per chiarezza un altro confronto in cui trovare i massimi e minimi di un ora di ieri sia con la scrittura classica che con il multiTimeFrame:

§ 7.2 – MTF esempi completi tipici

Vediamo ora come si applica il MTF con dei sistemi completi: uno di breakout e l’altro di falso breakout.

Una tecnica nota è quella di entrare al breakout di massimi importanti. In questo esempio compriamo il massimo di tre giorni fa.

Altro esempio classico. Spesso il mercato per trovare liquidita effettua dei falsi breakout di punti importanti, in particolare dei massimi e minimi importanti di giornata, oppure il massimo ed il minimo del giorno prima.

In questo sistema se il prezzo rompe il massimo di ieri e poi rientra allora si può pensare che sia un falso breakout e proviamo ad entrare short.

§ 7.3 – Numero operazioni timeframe superiore

In alcune strategie vogliamo utilizzare il MTF per consentire una sola operazione all’interno di ogni barra del timeframe superiore di riferimento.
Per ottenere questo comportamento possiamo utilizzare un flag che abilita l’ingresso all’inizio di ogni nuova barra del timeframe superiore e lo disattiva dopo l’esecuzione dell’operazione. La struttura di base è la seguente:

Qui non vogliamo più consentire una sola operazione per ogni ora, ma massimo 3 operazioni nella stessa ora.

Con il trading multitimeframe non ci limitiamo quindi a utilizzare informazioni provenienti da un timeframe superiore: possiamo anche stabilire quante operazioni consentire all’interno di ciascuna barra di quel timeframe.
Attraverso un flag possiamo limitare l’operatività a una sola operazione, mentre utilizzando un contatore possiamo impostare un numero massimo di operazioni.
Il timeframe superiore stabilisce la finestra temporale di riferimento, mentre flag e contatore determinano quanta operatività concedere all’interno di quella finestra.
In questo modo il MTF diventa non solo uno strumento per utilizzare informazioni provenienti da timeframe diversi, ma anche un efficace sistema per controllare e limitare la frequenza delle operazioni.

Torna in alto