In questo articolo descriviamo come effettuare il debug di Pinescript tramite i Grafici con Tradingview per le strategie di trading algoritmico, tramite alcuni esempi pratici e alcuni suggerimenti che potrebbero semplificare la vita. Chiunque abbia mai codificato in pine-script ha sicuramente notato che il debugging può essere una seccatura. Senza la possibilità di stampare informazioni e dati su un terminale, siamo costretti a tracciare i grafici di qualsiasi cosa e verificare se tutto è corretto, come desideriamo. Questo processo può essere ancora più laborioso se le variabili lavorano su scale diverse. L’approccio prevede spesso un lungo esercizio per visualizzare i diverse grafici, uno alla volta.
Debug di Pinescript tramite i Grafici con Tradingview
Dato che non possiamo usare un terminale, per ispezionare le variabili possiamo solamente tracciare i grafici di tutto quello che dobbiamo controllare. Nei prossimi paragrafi descriviamo come visualizzare i grafici per ogni tipo di variabile con alcuni suggerimenti e consigli generali.
Float e Int
I tipi numerici Float e Int non hanno bisogno di presentazioni. Sono la base dei grafici. Tuttavia, per coprire completamente l’argomento del debugging, dobbiamo brevemente introdurre un paio di concetti.
Per visualizzare un numero float o intero, dobbiamo inserire il valore come primo parametro alla chiamata del metodo plot()
. Ad esempio, plot(myint)
.
Sottolineiamo che visualizzare i numeri float e interi non è del tutto semplice. Nonostante possiamo visualizzare il grafico di qualsiasi valore float o intero, possiamo avere problemi di ridimensionamento. Cosa sono i “problemi di ridimensionamento”? Quando si visualizza il grafico di un numero intero, con valore pari a 8000, accanto a un float, con valore pari a 0,5, non riusciamo a vedere chiaramente uno dei due grafici perchè hanno ordini di grandezza troppo distanti. Questo tema è approndito nei successivi paragrafi.
Valori booleani
Le variabili booleane sono variabili che possono assumere solo i valori sono true
o false
. Se proviamo a visualizzare il grafico di un valore booleano direttamente come parametro della funzione plot()
otteniamo il seguente errore:
Add to Chart operation failed, reason: line 130: root_data expression of plot_11 has invalid type: series__bool expected series
Per eseguire il debug di un valore booleano, dobbiamo prima convertirlo in un tipo valido. Possiamo usare un operatore condizionale ternario per convertire un boolean in un float. Come mostrato nel seguente esempio, consideriamo una variabile x
che memorizza un valore true
o false
. (es. x = false
), quindi
x_int = x ? 1 : 0
Questa istruzione crea una nuova variabile chiamata x_int
. Se x
è true
allora si memorizza 1 in x_int
. In caso contrario, il valore di x
deve essere falso (perché certamente non è vero!) e quindi si memorizza 0 in x_int
. In questo modo, quando visualizziamo x_int
usando il comando plot(x_int)
, possiamo facilmente vedere ogni volta che x è vero o falso.
In alternativa, possiamo farlo direttamente all’interno del grafico senza creare una variabile x_int
, cioè all’interno della chiamata al metodo plot(x ? 1 : 0)
.
Stringhe
La gran parte delle variabili String sono sottoposte al debug tramite lo stesso metodo dei valori booleani. Tuttavia, prima di descrivere alcuni esempi di debug, dobbiamo introdurre un argomento correlato.
Se proviamo a visualizzare una stringa usando la variabile text
in uno dei grafici che la supportano, (ad esempio plotshape()
, plotchar()
, ecc…) potremmo spendere molto tempo per “debuggare” le stringhe. Tradingview fornisce una funzione tostring()
che converte il valore più recente di una serie in una stringa e lo visualizza solo quando vengono soddisfatte determinate condizioni. Potrebbe essere incredibilmente utile!
Ad esempio, supponiamo che stiamo visualizzando un grafico intraday ma vogliamo sapere qual è il valore più recente dell’ATR giornaliero. Se visualizziamo direttamente i valori ATR sul grafico principale, potrebbe essere disordinato e incorrere in problemi di ridimensionamento. E’ più pulito visualizzare solo i valori sopra la barra a intervalli regolari. Sfortunatamente, al momento, non è possibile farlo con Pine-script. Le funzioni di visualizzazione dei grafici prevedono solo stringhe costanti (stringhe che non cambiano mai o che non sono create dinamicamente).
Per aiutare a capire di cosa stiamo parlando, possiamo guardare il seguente grafico:
Sarebbe più utile e pulito visualizzare anche 0.0059
sotto le parole ATR. Per chi fosse interessato, il grafico precedente è stato creato con il seguente codice:
//@version=3
study("Daily ATR", overlay=true)
atr = security(tickerid, "D", atr(7))
is_newbar(res) =>
t = time(res)
change(t) != 0
// Visualizzare la nuova barra giornaliera
nb = is_newbar("D")
plotchar(nb, location=location.abovebar, text="ATR")
//plotchar(nb, location=location.abovebar, text=tostring(atr))
Se togliamo il commento all’ultima riga, riceviamo il seguente errore:
Add to Chart operation failed, reason: argument "text" accepts only constant string values
Se qualche lettore là fuori conosce una soluzione alternativa o qualcosa che ci è sfuggito, ci piacerebbe saperlo . Contattaci!
Uscire dai sentieri battuti….
Nel paragrafo precedente non abbiamo descritto come fare il debug di una stringa, ma spero che possa far risparmiare un po’ di tempo. Torniamo all’argomento principale.
Come accennato in precedenza, il debug delle stringhe è molto simile al debug dei valori booleani. Dobbiamo convertire la stringa in un valore che può essere visualizzato. Anche in questo caso è possibile utilizzare un operatore condizionale ternario per creare un valore visualizzabile. In generale, non ci sono molti scenari in cui è necessario eseguire il debug delle stringhe. Tuttavia, può essere utile nei casi dove usiamo il parametro options nella funzione input()
. Questo è particolarmente utile quando il codice deve prendere decisioni in base all’opzione selezionata.
Il seguente codice prevede un controllo su quale opzione è stata selezionata, e modifica il valore e il colore di conseguenza:
//@version=3
study("Daily ATR", overlay=false)
opts = input(defval='Hammer', title='Operation Mode', options=["Hammer", "Hanging", "Engulfing"])
operation_mode = opts == 'Hammer' ? 1 : opts == 'Hanging' ? 2 : opts == 'Engulfing' ? 3 : 0
plot_color = opts == 'Hammer' ? green : opts == 'Hanging' ? red : opts == 'Engulfing' ? purple : na
plot(operation_mode, color=plot_color, linewidth=2)
Funzioni e metodi utili
Ora che abbiamo descritto le basi del debug di Pinescript tramite i grafici con Tradingview, descriviamo alcuni argomenti e consigli generali sulla visualizzazione dei grafici che possono semplificarci la vita.
Stili di stampa
Quando si esegue il debug di molti valori diversi, può essere difficile riconoscere facilmente quale riga rappresenta una determinata variabile. Soprattutto se sono tutti visualizzate come semplici grafici a linee blu (i valori di default). L’uso di diversi stili e opzioni di stampa può aiutare alcuni dei risultati a distinguersi dalla massa.
- Plotshape() e Plotchar(): sono una buona opzione quando abbiamo eventi che si verificano raramente. Come nel precedente esempio dell’ATR, aiutano a contrassegnare gli eventi in modo ordinato.
- Colorazione dello sfondo: spesso trascurata, la colorazione dello sfondo può essere un ottimo modo per indicare uno stato attuale. Ad esempio, se stiamo visualizzando il grafico principale ma vogliamo sapere quando stiamo negoziando in condizioni di ipercomprato o ipervenduto.
Esempio di colore dello sfondo
Prendiamo l’esempio precedente e trasformiamolo in codice. Il seguente codice permette di cambiare il colore dello sfondo del grafico principale quando l’indicatore RSI è ipercomprato o ipervenduto.
//@version=3
study("RSI Backgound", overlay=true)
rsi = rsi(close, 14)
bcol = rsi > 70 ? red : rsi < 30 ? green : na
bgcolor(bcol)
Otteniamo il risultato nel seguente grafico:
Semafori
Se abbiamo complessi criteri di entrata/uscita che prevedono diversi filtri e conferme, possiamo avere difficoltà nel fare il debug dello script. Per tali strategie, possiamo usare un sistema a semaforo che fornisce lo stato di ogni controllo. Quando lo script non entra, si può verificare immediatamente quale condizione o filtro di ingresso si attiva.
Di seguito un semplice esempio:
//@version=3
strategy("Traffic Lights", overlay=false)
sma_check = close > sma(close, 14)
vol_check = volume > (volume[1] * 2)
close_check = close > open
sma_plot_col = sma_check ? green : red
vol_plot_col = vol_check ? green : red
close_plot_col = close_check ? green : red
longCondition = sma_check and vol_check and close_check
if(longCondition)
strategy.entry("Long", strategy.long)
shortCondition = not sma_check and not vol_check and not close_check
if(shortCondition)
strategy.entry("Short", strategy.short)
plotshape(2, title='SMA Check', color=sma_plot_col, style=shape.circle, location=location.absolute)
plotshape(4, title='Vol Check', color=vol_plot_col, style=shape.circle, location=location.absolute)
plotshape(6, title='Close Check',color=close_plot_col, style=shape.circle, location=location.absolute)
hline(1, linestyle=solid)
hline(3, linestyle=dashed)
hline(5, linestyle=dashed)
hline(7, linestyle=solid)
Il codice prevede tre semplici controlli. Verifica se abbiamo una chiusura al di sopra di un valore SMA, se il volume è aumentato e se abbiamo una chiusura al rialzo o al ribasso. L’immagine seguente mostra come appare su un grafico.
Possiamo facilmente vedere il risultato dei test per ogni barra. Si potrebbe obiettare che è ancora difficile individuare quale luce corrisponde a quale test. Tuttavia, dobbiamo ricordarci che questo è solo un esempio, possiamo modificare le forme, i colori, gli stili ecc. per poter identificare facilmente i singoli test. Inoltre, nonostante non sappiamo a quale test corrisponde, possiamo facilmente vedere che la prima riga è fallita e dare un’occhiata al titolo della riga.
Quando usiamo questo metodo evitiamo completamente il debug. Questo perché spesso pensiamo che il codice “avrebbe dovuto” fare qualcosa, ma dopo aver esaminato il controllo fallito, ci rendiamo presto conto che è corretto e andiamo avanti.
Gestire i grafici da tastiera
Se abbiamo molti grafici di test che non vogliamo visualizzare sempre, conoscere come gestire i grafici da tastiera può velocizzare notevolmente il tempo impiegato per commentare e rimuovere il commento. È il commento multilinea! Consiste nell’evidenziare una grande porzione di codice e quindi premere CTRL+/
(o Option+/
per gli utenti Mac). In questo modo commentiamo l’intero blocco di testo evidenziato. Un reale risparmio di tempo quando passiamo dai grafici di test ai grafici degli indicatori.
Risoluzione
Come accennato in precedenza, la risoluzione è la cosa principale a cui dobbiamo prestare attenzione quando effettuiamo il debug. Di conseguenza dobbiamo adattare i nostri grafici. Ad esempio, se stiamo tracciando i risultati di un test booleano (controllando se il risultato è vero o falso) con 0
e 1
, quindi visualizzarli nello stesso grafico principale, come quello di bitcoin, abbiamo un problema di visibilità.
In tali scenari possiamo prevedere alcune opzioni:
- Ridimensionare il valore booleano in qualcosa di più appropriato. Ad esempio, possiamo usare i valori
high
elow
in modo che si sposti dal massimo al minimo in linea con il prezzo. (es.x_int = x ? high : low
) - Usare una scala diversa. (tramite le opzioni di scala a sinistra, a destra o nessuna scala). Questo può scollegare l’indicatore dalla scala dei prezzi.
- Rimuovere i commenti dai grafici (se presenti) progettati per il grafico principale, quindi tracciare i grafici di testo in una sottotrama (
overlay=false
) al solo fine di test.
L’immagine precedente mostra un esempio per tracciare un indicatore Stocastico RSI sul grafico principale usando scale.none
. Di seguito il codice completo:
//@version=3
study(title="Stochastic RSI", shorttitle="Stoch RSI", overlay=true, scale=scale.none)
smoothK = input(3, minval=1)
smoothD = input(3, minval=1)
lengthRSI = input(14, minval=1)
lengthStoch = input(14, minval=1)
src = input(close, title="RSI Source")
rsi1 = rsi(src, lengthRSI)
k = sma(stoch(rsi1, rsi1, rsi1, lengthStoch), smoothK)
d = sma(k, smoothD)
plot(k, color=blue)
plot(d, color=orange)
h0 = hline(80)
h1 = hline(20)
fill(h0, h1, color=purple, transp=80)
Conclusione
Questo articolo era stato originariamente destinato a descrivere solamente il debug, ma si è ampliato con altri argomenti man mano che veniva scritto. Una volta acquisita familiarità con i metodi per convertire qualsiasi variabile in float o integer, il debugging diventa molto semplice e dipende solo dalle preferenze personali per la visualizzazione dei grafici. Per questo motivo metà dell’articolo descrivere le varie opzioni di visualizzazione.
In ogni caso, spero che l’articolo sia utile. Buon debug!
Codice completo
In questo articolo descriviamo come effettuare il debug di Pinescript tramite i Grafici con Tradingview per le strategie di trading algoritmico. Per il codice completo riportato in questo articolo, si può consultare il seguente repository di github:
https://github.com/datatrading-info/TradingView