Kit di codice del trader — Python e Pine Script
Sei frammenti da copiare: quattro in Python (caricamento del diario CSV, metriche, curva cumulativa con drawdown e dimensionamento della posizione con ATR) e due in Pine Script (range giornaliero rispetto all’ATR con avviso e finestre di sessione del piano sul grafico). Sono tutti strumenti ANALITICI: calcolano, tracciano grafici e ricordano le regole; nessuno genera segnali di acquisto/vendita o prende decisioni, perché questo è il compito del playbook. Identificatori eseguibili, API e nomi tecnici conservano l’inglese della documentazione di pandas e Pine Script e dei messaggi delle librerie; i commenti e i messaggi esplicativi sono tradotti in italiano rispettando il codice (lo stesso approccio usato dal laboratorio di IA per i prompt che riguardano il codice); le spiegazioni circostanti usano la lingua del corso e guidano passo per passo. Ambiente: l’installazione di Python e le prime esecuzioni sono trattate in 11.8; le intestazioni delle colonne del diario si trovano nel modulo F.
- Strumenti, non strategie: il codice calcola metriche dai TUOI dati e aiuta a rispettare il TUO piano; il confine è lo stesso della sezione «che cosa non fa l’IA» del modulo H, per le stesse ragioni
- Un formato di dati condiviso: i frammenti Python leggono le intestazioni del foglio di diario (modulo F); il tasso di successo include le operazioni in pareggio nel denominatore e l’aspettativa usa il risultato netto: sono le stesse definizioni del prompt P5
- Pine Script senza lookahead: S5 recupera i dati giornalieri con
lookahead=barmerge.lookahead_off; S6 non accede affatto a un timeframe superiore (usa solo la funzionetime). L’assenza di lookahead non dimostra l’assenza di repainting: la descrizione di S5 spiega che cosa vedi sulle barre storiche e in tempo reale. Sono le insidie ricercate da una revisione del codice con il prompt P3 - Il dimensionatore arrotonda il volume PER DIFETTO: nel convertire il rischio in lotti, arrotondare per eccesso aumenta sistematicamente il rischio oltre il piano; quella riga di codice distingue l’1% da «circa l’1%»
Prima di eseguire il codice: tre regole
- Leggi prima di eseguire. Ogni frammento è volutamente breve: dovresti comprenderne ogni riga. Modifica il codice che non capisci con l’aiuto di una revisione P3, senza procedere a tentativi; la regola vale a maggior ragione per frammenti provenienti da forum e chat.
- Entrano dati dai file; dal codice non escono decisioni. Gli script leggono un’esportazione del diario (nel formato del modulo F) e i parametri che fornisci esplicitamente. Producono numeri e grafici per la revisione settimanale; le conclusioni spettano a te, seguendo il processo di verifica del 15.10 e considerando dimensione del campione, dipendenze tra operazioni e incertezza del risultato.
- L’ambiente dell’articolo 11.8: Python 3.11 o successivo con
pandasematplotlib(l’installazione e il primo script sono spiegati lì); i frammenti S1–S4 sono stati rieseguiti il 17 settembre 2026 con Python 3.12.10, pandas 3.0.5 e matplotlib 3.11.1. Altre versioni non sono state testate. Incolla Pine Script nell’editor degli indicatori della tua piattaforma grafica; entrambi gli indicatori usano la versione 6.
Passaggi minimi per l’esecuzione: nel tuo ambiente Python 3.11+, verifica la versione con python --version, poi installa i pacchetti con python -m pip install pandas==3.0.5 matplotlib==3.11.1, salva S1+S2+S3 come analiza_dziennika.py e il CSV di prova come dziennik.csv, poi esegui python analiza_dziennika.py. S4 richiede soltanto la libreria standard. Incolla S5 e S6 separatamente nel Pine Editor. I due frammenti Pine sono stati confrontati con la documentazione v6; non sono stati compilati e i loro avvisi non sono stati testati in TradingView.
S1 · Caricamento del diario CSV
Python 3 · pandasIl punto di partenza per S2 e S3: legge l’esportazione del foglio del modulo F, controlla le intestazioni e il numero di campi, quindi ripulisce la colonna r_net . Nomi di colonna duplicati, intestazione vuota o troppi o troppo pochi campi interrompono l’importazione; lo script non sceglie fra due colonne dei risultati e non sposta i dati nell’indice. Rappresenta un campo vuoto con un separatore, per esempio ;A+;;0; una riga troncata è un caso diverso. Imposta separatore e carattere decimale secondo la variante CSV (PL: punto e virgola e virgola; EN: virgola e punto), insieme alla codifica: i file del generatore del modulo F usano UTF-8 e anche la variante «CSV UTF-8» salvata in Excel può essere letta come UTF-8; un’esportazione precedente con la pagina codici polacca può richiedere cp1250. Controlla il formato di salvataggio, perché la sola lingua dell’interfaccia non determina la codifica. Un valore vuoto di r_net insieme a un valore vuoto di close_time_utc indicano che l’operazione non è ancora chiusa (e viene saltata); un’ora di chiusura senza risultato indica una registrazione incompleta e interrompe i calcoli. Un valore non vuoto non interpretabile come numero (anche «NA» o un trattino) interrompe lo script e segnala il numero del record; lo stesso accade per un’operazione chiusa senza ora di chiusura nel formato del modulo F (2026-07-08 13:15), perché altrimenti bisognerebbe indovinare la sequenza della curva.
import pandas as pd
CSV_PATH = "dziennik.csv" # esportazione del diario (struttura dell’appendice F)
CSV_SEP = ";" # ";" per CSV con impostazioni PL, "," per EN
DECIMAL = "," # "," per CSV con impostazioni PL, "." per EN
ENCODING = "utf-8-sig" # il generatore dell’appendice F scrive UTF-8 (BOM gestito); vecchi CSV con codepage polacca possono richiedere "cp1250"
REQUIRED = ["r_net", "setup", "setup_class", "error_code", "close_time_utc"]
# Leggere un file locale e validarne la struttura PRIMA di creare un DataFrame.
# pandas.read_csv può rinominare intestazioni duplicate o dedurre un indice dai campi aggiuntivi.
import csv
try:
with open(CSV_PATH, encoding=ENCODING, newline="") as source:
reader = csv.reader(source, delimiter=CSV_SEP, strict=True)
header = next(reader, None)
if not header:
raise SystemExit("Impossibile leggere il CSV: intestazione vuota.")
if any(not name or name != name.strip() for name in header):
raise SystemExit("Nome di colonna vuoto o con spazi ai margini — correggere l’intestazione CSV.")
duplicates = sorted({name for name in header if header.count(name) > 1})
if duplicates:
raise SystemExit(f"Colonne duplicate: {duplicates} — risolverle nel diario.")
rows, record_indexes = [], []
for index, row in enumerate(reader):
if not row: # un record CSV completamente vuoto
continue
if len(row) != len(header):
raise SystemExit(f"Record {index + 1}: previsti {len(header)} campi, ricevuti {len(row)} "
f"— controllare separatori e virgolette; nessun campo è stato scartato.")
rows.append(row)
record_indexes.append(index)
df = pd.DataFrame(rows, columns=header, index=record_indexes, dtype="string").replace("", pd.NA)
except UnicodeDecodeError:
raise SystemExit(f"Impossibile decodificare {CSV_PATH} come {ENCODING} — verificare UTF-8 o la vecchia cp1250.") from None
except (OSError, csv.Error) as exc:
raise SystemExit(f"Impossibile leggere {CSV_PATH}: {exc}") from None
missing = [c for c in REQUIRED if c not in df.columns]
if missing:
raise SystemExit(f"Colonne mancanti: {missing} — confrontare intestazioni con l’appendice F e l’impostazione CSV_SEP.")
raw = df["r_net"] # risultato vuoto consentito solo se è vuoto anche l’orario di chiusura
txt = raw.astype("string").str.strip().str.replace(DECIMAL, ".", regex=False) # interpretare la colonna direttamente: una cella errata non deve nascondere quelle leggibili
r = pd.to_numeric(txt, errors="coerce").astype("Float64") # evitare overflow degli interi nelle somme successive
r = r.where(r.abs() != float("inf")) # nemmeno inf è un multiplo R valido
invalid = raw.notna() & r.isna() # compilato, ma non leggibile come numero
if invalid.any():
raise SystemExit(f"r_net non valido nei record {(df.index[invalid] + 1).tolist()} "
f"(record 1 = prima riga sotto l’intestazione) — controllare valori e DECIMAL; "
f"NA, trattini e infinito non sono numeri.")
blank = df.isna().all(axis=1) # intera riga vuota = riga inutilizzata del foglio (esportazione XLSX integrale), non un’operazione
df, r = df[~blank], r[~blank]
has_close = df["close_time_utc"].fillna("").str.strip().ne("")
incomplete = r.isna() & has_close
if incomplete.any():
raise SystemExit(f"r_net mancante per i record chiusi {(df.index[incomplete] + 1).tolist()} "
f"— completare il risultato netto prima di calcolare le metriche.")
open_trades = int(r.isna().sum())
df = df.assign(r_net=r).dropna(subset=["r_net"]) # indice conservato = numeri di record per il messaggio seguente
# curva e drawdown richiedono ordine cronologico (appendice F: per orario di chiusura); un’operazione chiusa senza orario leggibile arresta lo script
close_text = df["close_time_utc"].fillna("").str.strip()
has_time = close_text.str.fullmatch(r"\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:\d{2})?")
closed = pd.to_datetime(close_text.where(has_time), errors="coerce", format="ISO8601", utc=True) # l’appendice F scrive 2026-07-08 13:15; il formato fisso rende il controllo indipendente dall’ordine delle righe; utc=True evita errori con suffissi inattesi "Z"/"+00:00"
if closed.isna().any():
raise SystemExit(f"close_time_utc illeggibile nei record {(df.index[closed.isna()] + 1).tolist()} "
f"— ogni operazione chiusa richiede un orario nel formato dell’appendice F (2026-07-08 13:15); correggere il diario, non lo script.")
df = df.assign(_t=closed).sort_values("_t", kind="stable").drop(columns="_t").reset_index(drop=True)
print(f"Caricate {len(df)} operazioni chiuse ({open_trades} riga/righe ignorata/e: senza orario di chiusura e senza r_net).")
Ottieni un DataFrame, df, pronto per i frammenti successivi e ordinato per ora di chiusura (curva e drawdown sono calcolati in tale ordine), oltre al numero delle operazioni aperte saltate (una riga vuota è un record interamente vuoto, come nell’esportazione di un intero foglio XLSX: lo script non conta queste righe; una riga con dati ma senza risultato né ora di chiusura viene saltata perché non ancora chiusa; una registrazione chiusa senza risultato interrompe lo script). Se l’esecuzione si interrompe indicando un elenco di record, correggi le righe segnalate nel diario, non lo script; se è interessata l’intera colonna, controlla anche la costante DECIMAL . La numerazione dei record inizia dopo l’intestazione e include i record vuoti; un campo tra virgolette può contenere un separatore o un a capo e appartenere comunque allo stesso record. Ogni operazione deve comparire una sola volta: controlla gli identificatori trade_id prima di unire le esportazioni; S1 non elimina i duplicati dalla cronologia. Una data senza ora non basta per ricostruire la sequenza. Un orario senza indicazione del fuso viene trattato come UTC; un offset ISO 8601 esplicito viene convertito in UTC. A parità di orario lo script conserva l’ordine dei record: stabiliscilo nel diario, perché influenza il percorso del drawdown.
S2 · Metriche del diario
Python 3 · pandasLe stesse definizioni del prompt P5 e del riepilogo del foglio: il tasso di successo include nel denominatore le operazioni in pareggio; il profit factor restituisce un messaggio invece di dividere per zero; l’aspettativa è la media degli R netti (r_net); il drawdown è misurato dalla curva cumulativa che parte da 0 R (la prima perdita è già un drawdown, come nella formula del foglio F). Esegui dopo S1. Le definizioni delle metriche sono condivise, ma il trattamento degli errori differisce da P5: S1 interrompe l’analisi quando un’operazione chiusa ha un risultato non valido, mentre P5 indica di saltare quella riga e contarla. Confronta i risultati solo dopo aver stabilito quali operazioni sono incluse in entrambi i campioni.
import math
def metrics(r):
"Metriche principali del diario su una serie di multipli R netti.\n Definizioni (come nel pannello dell’appendice F):\n - percentuale di successo: operazioni con r > 0 su TUTTE le valide (break-even resta nel denominatore)\n - profit factor: somma degli r positivi divisa per abs(somma degli r negativi)\n - expectancy: media aritmetica di r (al netto dei costi)\n - drawdown massimo: massima caduta della curva R cumulata dal suo massimo progressivo,\n con partenza da 0 R (una prima perdita di -1 R è già un drawdown di 1 R)"
n = len(r)
if n == 0:
raise SystemExit("Nessuna operazione valida — nulla da misurare.")
try:
r = r.astype(float)
except (TypeError, ValueError):
raise SystemExit("Le metriche richiedono valori R netti numerici — eseguire prima S1.") from None
if not r.map(math.isfinite).all():
raise SystemExit("Le metriche richiedono valori R netti finiti — eseguire prima S1.")
wins = r[r > 0]
losses = r[r < 0]
equity = r.cumsum()
peak = equity.cummax().clip(lower=0) # appendice F: MAX(0; massimo progressivo)
drawdown = peak - equity
try:
total = math.fsum(r)
pf_value = None if losses.empty else math.fsum(wins) / abs(math.fsum(losses))
except (OverflowError, ValueError, ZeroDivisionError):
raise SystemExit("Intervallo numerico superato — controllare i valori R; nessuna metrica restituita.") from None
if (not equity.map(math.isfinite).all() or not drawdown.map(math.isfinite).all()
or (pf_value is not None and not math.isfinite(pf_value))):
raise SystemExit("Intervallo numerico superato — controllare i valori R; nessuna metrica restituita.")
pf = "nessuna perdita nel campione" if pf_value is None else round(pf_value, 2)
return {
"trades": n,
"win_rate": round(len(wins) / n, 3),
"profit_factor": pf,
"expectancy_R": round(total / n, 3),
"sum_R": round(total, 2),
"max_drawdown_R": round(drawdown.max(), 2),
}
for key, value in metrics(df["r_net"]).items():
print(f"{key:>16}: {value}")
Ottieni sei metriche per la revisione settimanale; se non ci sono perdite, PF è un messaggio anziché un numero. Se i valori superano l’intervallo di calcolo, lo script interrompe l’analisi invece di restituire inf, NaN o un drawdown apparentemente nullo. WR = 0.4 significa 40%. PF è calcolato in R, non in PLN; con un rischio monetario variabile i risultati possono differire. I costi sono già inclusi in r_net ; S2 non li sottrae di nuovo. Non aspettarti una valutazione del tuo vantaggio dalla sola media, né semplicemente dal superamento di 20 o 50 operazioni. Trovi le definizioni del riepilogo nel modulo F e il piano per selezione del campione, costi e validazione nel modulo N.
S3 · Curva cumulativa e drawdown
Python 3 · pandas + matplotlibTraccia la curva cumulativa in R con, sotto, il drawdown dal picco e salva un PNG accanto al file CSV specificato da CSV_PATH (S1), indipendentemente dalla directory da cui esegui lo script. La curva mostra la sequenza dei risultati e i gruppi di perdite che scompaiono nei numeri aggregati. È una somma di R, non il saldo del conto in PLN o il capitale in percentuale: con un rischio monetario variabile non riproduce le variazioni del saldo. Il grafico non include versamenti, prelievi o risultati delle posizioni aperte. Esegui dopo S1.
import math
import matplotlib.pyplot as plt
from pathlib import Path
if len(df) == 0:
raise SystemExit("Nessuna operazione chiusa — nulla da tracciare.")
equity = df["r_net"].astype(float).cumsum()
drawdown = equity.cummax().clip(lower=0) - equity # stessa definizione di S2 e appendice F (la curva parte da 0 R)
if not equity.map(math.isfinite).all() or not drawdown.map(math.isfinite).all():
raise SystemExit("Intervallo numerico superato — controllare i valori R; nessun grafico salvato.")
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 6), sharex=True,
gridspec_kw={"height_ratios": [3, 1]})
x = [0, *(equity.index + 1)] # operazione 0 = punto iniziale di 0 R da cui si misura il drawdown
ax1.plot(x, [0.0, *equity.values])
ax1.set_ylabel("risultato (R)")
ax1.set_title("Curva dei risultati — R netti cumulati")
ax1.grid(True, alpha=0.3)
ax2.fill_between(x, [0.0, *(-drawdown.values)], 0, alpha=0.5)
ax2.set_ylabel("drawdown (R)")
ax2.set_xlabel("operazione n.")
ax2.grid(True, alpha=0.3)
fig.tight_layout()
PNG_PATH = Path(CSV_PATH).with_name("equity_curve.png") # accanto al file del diario, indipendentemente dalla directory di lavoro
fig.savefig(PNG_PATH, dpi=150)
plt.close(fig)
print(f"Salvato: {PNG_PATH}")
Ottieni un file equity_curve.png accanto al diario; la curva parte da 0 R (operazione 0), da cui viene misurato il drawdown. Il pannello inferiore mostra il drawdown degli R cumulativi dal picco (partendo da 0 R, come in S2 e nel foglio F) su tutta la cronologia: non è la perdita settimanale. Verifica separatamente, settimana per settimana, il limite settimanale del piano (modulo E), usando l’unità e la regola di azzeramento specificate nel piano.
Salva come dziennik.csv (UTF-8) accanto allo script combinato S1+S2+S3 ed eseguilo. Il file contiene soltanto le colonne necessarie a S1; l’esportazione completa del modulo F (26 colonne) viene caricata nello stesso modo. L’ultima riga è un’operazione aperta (r_net vuoto); le prime due operazioni chiuse sono perdite, quindi il drawdown è misurato da 0 R.
trade_id;close_time_utc;setup;setup_class;r_net;error_code 2026-041;2026-07-08 13:15;wybicie-azja-londyn;A+;-1,00;5 2026-042;2026-07-09 16:40;powrot-do-sredniej;B;-1,08;3 2026-043;2026-07-10 09:05;wybicie-azja-londyn;A+;1,83;0 2026-044;2026-07-13 12:20;wybicie-azja-londyn;B;0,00;0 2026-045;2026-07-14 14:30;powrot-do-sredniej;C;2,40;0 2026-046;;wybicie-azja-londyn;B;;
Risultato atteso (Python 3.12.10, pandas 3.0.5, matplotlib 3.11.1; esecuzione del 17 settembre 2026):
Caricate 5 operazioni chiuse (1 riga/righe ignorata/e: senza orario di chiusura e senza r_net).
trades: 5
win_rate: 0.4
profit_factor: 2.03
expectancy_R: 0.43
sum_R: 2.15
max_drawdown_R: 2.08
Salvato: equity_curve.png
Calcolo da verificare a mano: vincite di 1.83 + 2.40 = 4.23 R, perdite di 1.00 + 1.08 = 2.08 R → PF 2.03; totale 2.15 R / 5 = 0.43 R; curva −1.00 → −2.08 → −0.25 → −0.25 → 2.15, con un picco iniziale di 0 R → drawdown di 2.08 R (senza il punto a 0 R sarebbe 1.08 R: è la distinzione alla base della definizione del modulo F). Il risultato si riferisce esattamente a questo file e alle versioni indicate; se differisce, controlla nell’ordine dati (separatore, carattere decimale, codifica, ordine delle righe), costanti di S1, codice e versioni dei pacchetti.
S4 · Dimensionamento della posizione con ATR
Python 3 · libreria standardVolume in lotti per una distanza dello stop di k × ATR: l’importo a rischio deriva da capitale e percentuale, la distanza dall’ATR e il volume è arrotondato PER DIFETTO al passo dei lotti del tuo conto (i parametri lot_step e min_lot , entrambi con valore predefinito 0.01), affinché il rischio PIANIFICATO non superi il budget. La perdita effettiva può essere maggiore: il calcolo esclude slippage, gap oltre lo stop, spread, commissioni e swap. Capitale e valore del pip devono essere nella stessa valuta del conto; verifica separatamente volume massimo e margine richiesto nelle specifiche. Inserisci l’ ATR in pip (EURUSD 0.0080 → 80; USDJPY 0.80 → 80; la dimensione del pip è spiegata nel profilo della coppia, modulo B); il valore del pip per 1 lotto è nelle specifiche dello strumento (oppure puoi calcolarlo con il calcolatore del modulo C).
import math
from decimal import Decimal
from fractions import Fraction
def atr_position_size(capital, risk_pct, atr_pips, atr_mult, pip_value_per_lot,
lot_step=0.01, min_lot=0.01):
"Volume in lotti per uno stop di atr_mult × ATR.\n atr_pips: ATR in PIP, non in unità di prezzo (EURUSD ATR 0.0080 -> 80; USDJPY ATR 0.80 -> 80 — dimensione del pip della coppia).\n pip_value_per_lot: valore di 1 pip per 1.00 lotto, nella valuta del conto\n (es. ~10 USD per EURUSD su conto USD — verificare le specifiche).\n lot_step / min_lot: passo e minimo di volume del TUO conto (0.01 è comune, non universale).\n Arrotonda PER DIFETTO a multipli di lot_step misurati da zero. L’aritmetica delle frazioni\n conserva gli input decimali senza dipendere dalla precisione globale di Decimal.\n Il rischio pianificato non è la perdita massima: il modello non include slippage, gap, spread e swap."
inputs = (capital, risk_pct, atr_pips, atr_mult, pip_value_per_lot, lot_step, min_lot)
if any(isinstance(x, bool) or not isinstance(x, (int, float, Decimal)) for x in inputs):
raise ValueError("Usare valori numerici, non testo o booleani (i decimali Python usano il punto).")
decimals = tuple(Decimal(str(x)) for x in inputs)
if not all(x.is_finite() and x > 0 for x in decimals):
raise ValueError("Tutti gli input devono essere numeri finiti e positivi.")
c, p, a, k, v, step, minimum = map(Fraction, decimals)
if p > 100:
raise ValueError("risk_pct è una percentuale del capitale (1.0 = 1%).")
risk_amount = c * p / 100
sl_pips = a * k
lots = math.floor(risk_amount / (sl_pips * v * step)) * step
if lots < minimum:
return {"warning": "Nessun volume ammissibile per lot_step e min_lot entro il budget di rischio."}
exact = {"risk_amount": risk_amount, "sl_pips": sl_pips,
"lots": lots, "planned_risk": lots * sl_pips * v}
try:
result = {key: float(value) for key, value in exact.items()}
except OverflowError:
raise ValueError("Gli input superano l’intervallo numerico di output.") from None
if not all(math.isfinite(value) and value > 0 for value in result.values()):
raise ValueError("Gli input superano l’intervallo numerico di output.")
return result # float per visualizzare; nessun ulteriore arrotondamento di stop o importi monetari
print(atr_position_size(capital=10_000, risk_pct=1.0,
atr_pips=80, atr_mult=1.5, pip_value_per_lot=10.0))
# {'risk_amount': 100.0, 'sl_pips': 120.0, 'lots': 0.08, 'planned_risk': 96.0}
Ottieni i lotti arrotondati per difetto al passo e il corrispondente importo a rischio PIANIFICATO (nel modello senza costi, ≤ al budget; la perdita effettiva può essere maggiore). Il passo è misurato da zero; verifica che il tuo conto usi questa griglia di volume. Stop e importi monetari non subiscono ulteriori arrotondamenti: per esempio, ATR di 0.26 pip × 1.25 dà 0.325 pip, non 0.3. Il risultato viene restituito come valori float per la lettura, mentre il numero dei passi di lotto è calcolato con frazioni esatte; il minimo incremento di prezzo dello strumento va comunque verificato separatamente. Se adegui lo stop a tale incremento, ricalcola il volume. Non aspettarti una decisione sull’ingresso: il dimensionatore calcola «quanto», mai «se».
S5 · Range giornaliero rispetto all’ATR con avviso
Pine Script v6 · indicatoreUno strumento per comprendere la volatilità (indicatore intraday): sulle barre in tempo reale mostra quale percentuale dell’ATR giornaliero il mercato ha già «consumato» e avvisa quando viene superata una soglia; è il momento di consultare il piano, non di inseguire il prezzo. I dati giornalieri sono recuperati senza lookahead (senza valori futuri); sulle barre storiche, request.security mantiene l’ultimo valore giornaliero confermato fino alla fine del periodo D successivo, il cui nuovo risultato compare sull’ultima barra intraday di tale periodo. In tempo reale recupera il range e l’ATR in formazione della candela D corrente, perciò le letture precedenti possono cambiare dopo un ricaricamento (repainting). Un giorno è la candela D del fornitore di dati, non un giorno di calendario in Europe/Warsaw. Anche l’ATR al denominatore cambia durante la giornata; il 100% non è un limite al movimento del prezzo. Il metodo non può ricostruire sulle barre storiche i successivi attraversamenti della soglia avvenuti oggi.
//@version=6
indicator("Range giornaliero rispetto ad ATR (strumento di contesto)", overlay=false)
if not timeframe.isintraday
runtime.error("Usare un grafico intraday temporale inferiore a 1D.")
atrLen = input.int(14, "Lunghezza ATR", minval=2)
warnPct = input.int(80, "Avvisa quando il range giornaliero raggiunge % di ATR", minval=10, maxval=200)
// Storico: ultimo valore D confermato, aggiornato alla FINE di ogni periodo D.
// Tempo reale: valori D in formazione; le letture passate possono ridisegnarsi al ricaricamento.
dayHigh = request.security(syminfo.tickerid, "D", high, lookahead=barmerge.lookahead_off)
dayLow = request.security(syminfo.tickerid, "D", low, lookahead=barmerge.lookahead_off)
dayAtr = request.security(syminfo.tickerid, "D", ta.atr(atrLen), lookahead=barmerge.lookahead_off)
rangePct = dayAtr > 0 ? 100.0 * (dayHigh - dayLow) / dayAtr : na
plot(rangePct, "Range giornaliero come % di ATR", linewidth=2)
hline(100, "100% di ATR")
hline(warnPct, "Livello di avviso", linestyle=hline.style_dotted)
alertcondition(ta.crossover(rangePct, warnPct),
title="Range ha raggiunto % di ATR",
message="Il range giornaliero ha raggiunto la tua % di ATR — rileggere il piano prima di ogni nuovo ingresso.")
Ottieni un pannello sotto il grafico e una condizione di avviso; crea tu l’avviso nella piattaforma dopo aver aggiunto l’indicatore, selezionando «Range ha raggiunto % di ATR». Usa candele intraday standard basate sul tempo; i dati Heikin Ashi/Renko possono avere caratteristiche diverse. Una lettura mancante (na) indica che l’ATR o i dati necessari non sono disponibili, non lo 0%. La condizione richiede un passaggio da un valore ≤ alla soglia a un valore > alla soglia: il semplice permanere sopra non attiva un altro avviso. «Once Per Bar Close» limita gli avvisi alla chiusura della candela intraday, ma non conferma l’intera candela D. Ricrea l’avviso dopo aver modificato i parametri. Non aspettarti un segnale direzionale: una lettura elevata dice «il movimento è già avvenuto»; il playbook indica come comportarti.
S6 · Finestre di sessione del piano sul grafico
Pine Script v6 · indicatoreLa sezione 3 del piano (modulo E) disegnata sul grafico: evidenzia gli orari in cui PUOI aprire posizioni e avvisa quando la finestra si chiude. Imposta il fuso IANA esatto dichiarato nel piano e inserisci le sue finestre orarie nello stesso fuso. Europe/London, per esempio, segue GMT/BST in base alla data. Il codice mantiene Europe/Warsaw come caso regionale (CET/CEST); sostituisci questo valore predefinito se il piano usa un altro fuso. Per impostazione predefinita le finestre valgono dal lunedì al venerdì; un’opzione le estende a tutti i giorni. L’evidenziazione conferma soltanto l’orario previsto dal piano, non le altre condizioni d’ingresso. Usa candele intraday standard basate sul tempo.
//@version=6
indicator("Finestre di sessione del piano di trading", overlay=true)
if not timeframe.isintraday
runtime.error("Usare un grafico intraday temporale inferiore a 1D.")
// Caso regionale: sostituisci il valore predefinito con il fuso IANA esatto del piano.
tz = input.string("Europe/Warsaw", "Fuso IANA del piano")
win1 = input.session("0900-1200", "Finestra 1")
win2 = input.session("1400-1700", "Finestra 2")
weekdaysOnly = input.bool(true, "Solo da lunedì a venerdì")
days = weekdaysOnly ? ":23456" : ":1234567"
inWin = not na(time(timeframe.period, win1 + days, tz)) or not na(time(timeframe.period, win2 + days, tz))
bgcolor(inWin ? color.new(color.teal, 88) : na, title="Dentro una finestra del piano")
windowJustClosed = inWin[1] and not inWin
alertcondition(windowJustClosed,
title="Finestra del piano chiusa",
message="La tua finestra operativa si è appena chiusa — gestire solo posizioni aperte, nessun nuovo ingresso (piano, sezione 3).")
Ottieni uno sfondo evidenziato durante gli orari operativi e una condizione di avviso alla chiusura della finestra («Finestra del piano chiusa»: crea l’avviso nella piattaforma dopo aver aggiunto l’indicatore). L’avviso rileva la prima candela fuori dalla finestra che segue una candela al suo interno, quindi non garantisce una notifica all’esatto orario di chiusura: senza una nuova candela e un aggiornamento dei dati non effettua controlli. Usa un timeframe le cui aperture e chiusure siano allineate ai confini della finestra. Per esempio, su M15, con finestra 09:00–12:00 e una candela delle 12:00 disponibile, l’evidenziazione termina alle 12:00 e la condizione è attiva su quella prima candela esterna. «Once Per Bar» può notificare al primo aggiornamento; «Once Per Bar Close» solo alla chiusura. Le finestre sovrapposte formano un’unione: la fine della prima non chiude la seconda. Ricrea l’avviso dopo aver modificato gli orari. Non aspettarti il blocco degli ordini: l’indicatore ricorda il piano, mentre la checklist prima dell’operazione ne impone il rispetto.
Sei frammenti con titoli in un unico file di testo, istruzioni di configurazione e versioni delle librerie, seguiti dal CSV di prova e dal risultato atteso: da archiviare accanto al diario o conservare nel tuo repository. Il TXT combina linguaggi diversi: non eseguire tutto il file come Python. Scegli S1+S2+S3, S4 indipendente oppure un singolo indicatore Pine.
Domande frequenti
Perché il codice conserva nomi tecnici in inglese?
I nomi di API, funzioni e parametri conservano l’inglese della documentazione di pandas e Pine Script e dei messaggi d’errore delle librerie. In questo kit i commenti e i messaggi esplicativi sono in italiano, mantenendo identificatori e logica; il laboratorio di IA segue la stessa separazione nei prompt sul codice (modulo H, P3). Le descrizioni esterne spiegano CHE COSA fa il codice e quando usarlo; i commenti interni spiegano COME. L’eccezione della versione polacca di P5 (commenti polacchi nel codice generato appositamente per l’utente) riguarda codice occasionale, non una libreria. L’adattamento linguistico del kit conserva programmi e formati eseguibili.
Come eseguo i frammenti Python?
11.8 ti guida passo per passo nell’installazione di Python, dell’ambiente e dei pacchetti; pandas e matplotlib sono sufficienti per questo kit. Unisci i frammenti S1–S3 in un file, analiza_dziennika.py (con S1 all’inizio), ed esegui python analiza_dziennika.py nella directory contenente l’esportazione del diario; S4 funziona in modo indipendente. Il percorso relativo CSV_PATH si riferisce alla directory di lavoro del terminale. Parti dal CSV di prova e analizza una copia del tuo diario reale; equity_curve.png viene sovrascritto all’esecuzione successiva. Se il terminale restituisce un errore che non capisci, incolla codice e messaggio completo in una revisione P3 del modulo H, anziché procedere a tentativi.
Posso modificare ed estendere questi frammenti?
Servono proprio a questo: è un kit INIZIALE. Estensioni naturali sono metriche per setup (raggruppa per la colonna setup prima di chiamare la funzione S2), filtri per error_code per calcolare l’aspettativa delle esecuzioni senza errori oppure curve separate per le classi A+/B. Due regole per le modifiche: sottoponi ogni cambiamento a una revisione P3 (soprattutto ciò che coinvolge request.security in Pine) e versiona sia le definizioni delle metriche sia le regole della strategia. Correggi subito un errore di calcolo e ricalcola con lo stesso metodo i periodi confrontati; documenta una modifica delle regole della strategia nel protocollo di test (modulo N) e verificala su dati nuovi. La fine di un trimestre non giustifica di per sé una modifica, né il trovarsi a metà trimestre giustifica il mantenimento di un errore.
Perché il kit non contiene strategie o EA?
Per lo stesso motivo per cui il laboratorio di IA non genera segnali: una strategia pronta presa da internet ha un vantaggio sconosciuto, ipotesi sconosciute e nessun legame con il tuo piano; un EA che esegue sul tuo conto la logica di un’altra persona significa delegare decisioni di cui paghi tu solo le conseguenze. Il codice del corso rafforza il processo (misurazione, visualizzazione e rispetto del piano), anziché sostituirlo. Se vuoi automatizzare una tua strategia già testata, il percorso passa dal backtest del 15.4, dal protocollo di test del modulo N e da una revisione del codice P3, non dalla copia di script «redditizi».
math.floor in S4 al posto di round: la macchina arrotonda per difetto senza discutere; l’uomo arrotonda per eccesso trovando una giustificazione.Materiali collegati del corso
- 11.8 Python nel trading — configurazione dell’ambiente, primo script e uso dei pacchetti
- Modulo F — foglio di diario — il formato CSV letto da S1–S3 e le stesse metriche espresse con formule del foglio di calcolo
- Modulo H, prompt P3 — revisione di ogni modifica a questo codice (lookahead, repainting, errori logici)
- Sezione strumenti — calcolatori — valore del pip e dimensionamento della posizione nel browser, per verificare i risultati di S4
- Modulo E — modello del piano — finestre e limiti operativi che S6 disegna sul grafico
- 15.10 Verifica della strategia — interpretazione rigorosa dei numeri prodotti dal kit
Fonti
- Documentazione: pandas 3.0.5 e matplotlib 3.11.1 (funzioni usate in S1–S3); Python: lettura CSV e aritmetica con Fraction (validazione del formato e calcolo esatto del numero di passi di lotto); i frammenti S1–S4 sono stati eseguiti su dati sintetici il 17 settembre 2026 con Python 3.12.10; TradingView Pine Script v6: altri timeframe e dati, sessioni, ora e fusi orari, avvisi (request.security con parametro lookahead e repainting, hline, input.session, alertcondition); il codice S5–S6 è stato rivisto rispetto alla documentazione, senza compilazione.
- Riferimenti interni: 11.8 Python nel trading (ambiente), 15.9 (definizioni delle metriche e formato del diario), 15.10 (principi per trarre conclusioni): questo kit ne è un’implementazione pratica e condensata.
- Van K. Tharp, Trade Your Way to Financial Freedom, 2ª ed., McGraw-Hill 2007: multipli di R e aspettativa, il linguaggio condiviso di S2, foglio F e prompt P5.