Sei sulla pagina 1di 34

Introduzione all’uso di MATLAB

—————
Salti Condizionati
Cicli Iterativi
Functions e Subfunctions
—————
Appunti per l’insegnamento di
Metodi Computazionali per la Finanza
Anno Accademico 2017/2018

Riccardo Cambini
Dipartimento di Economia e Management
Università di Pisa,
Via Cosimo Ridolfi 10, 56124 Pisa, ITALY
E-mail: riccardo.cambini@unipi.it

Versione Maggio 2018

Piattaforma E-learning : https://moodle.ec.unipi.it/course/view.php?id=513

1
Salti Condizionati e Cicli Iterativi
(Live Script realizzato con MATLAB versione 2018a)

clear % si svuota preliminarmente il Workspace di MATLAB per evitare problemi

Salto Condizionato "if"


Spesso si ha l'esigenza di eseguire dei comandi solamente nel caso in cui una certa condizione sia
verificata. Il seguente comando verifica preliminarmente se la "condizione_vero/falso" è vera oppure falsa;
nel caso in cui la condizione sia vera viene eseguita la "Lista_Comandi", se è invece falsa non succede
niente.

if condizione_vero/falso
Lista_Comandi;
end

Si osservi come il comando "if" debba essere chiuso da un "end", e come l'editor di MATLAB riconosca il
comando e lo evidenzi in colore blu. E' possibile aggiungere alcune opzioni al comando "if":

if condizione_vero/falso
Lista_Comandi_1;
else
Lista_Comandi_2;
end

Questo comando verifica preliminarmente se la "condizione_vero/falso" è vera oppure falsa; nel caso
in cui la condizione sia vera viene eseguita la "Lista_Comandi_1", se è invece falsa viene eseguita la
"Lista_Comandi_2". Si capisce meglio adesso perché questi comandi sono chiamati "salti condizionati", a
seconda infatti della "condizione_vero/falso" si salta ad eseguire una parte di codice ("Lista_Comandi_1")
oppure un'altra ("Lista_Comandi_2") e poi si salta alla fine del comando "if" (ovvero al "end"). Il salto
condizionato "if" si può ulteriormente generalizzare:

if condizione_vero/falso_1
Lista_Comandi_1;
elseif condizione_vero/falso_2
Lista_Comandi_2;
elseif condizione_vero/falso_3
Lista_Comandi_3;
else
Lista_Comandi_4;
end

Questo comando verifica inizialmente la "condizione_vero/falso_1"; se è vera esegue la "Lista_Comandi_1",


se è falsa va a verificare la "condizione_vero/falso_2"; se quest'ultima è vera esegue la "Lista_Comandi_2",
se è falsa va a verificare la "condizione_vero/falso_3"; se quest'ultima è vera esegue la "Lista_Comandi_3",
se è falsa esegue la "Lista_Comandi_4". Ovviamente, l'opzione "else" non è obbligatoria e poteva essere
non presente.

1
Si osservi che una sola delle 4 "Liste Comandi" viene eseguita, si osservi inoltre che quando una "condizione
vero/falso" è vera non si vanno a verificare le condizioni logiche successive, si esegue la lista comandi
corrispondente e si salta poi alla fine del comando "if" (ovvero al "end").

Vediamo un semplice esempio:

x=-5; % definisce la variabile x


if x>0 % se x è positivo
p=1; % p prende il valore 1
elseif x<0 % altrimenti se x è negativo
p=-1; % p prende il valore -1
else % altrimenti, in tutti gli altri casi,
p=0; % p prende il valore 0
end
p % mostra il valore di p

p = -1

Ciclo Iterativo "for"


I cicli iterativi sono utilizzati per ripetere un certo numero prefissato di volte un determinato gruppo di
comandi. Ad esempio:

for i=1:n
Lista_Comandi;
end

Si osservi come il comando "for" debba essere chiuso da un "end", e come l'editor di MATLAB riconosca
il comando e lo evidenzi in colore blu. Questo comando continua ad eseguire la "Lista_Comandi",
incrementando ogni volta l'indice "i", fintanto che "i" è minore o uguale ad "n"; quando "i" supera "n" si esce
dal ciclo continuando con i comandi dopo la "end". Nello specifico accade quanto segue:

• "i" prende il valore iniziale 1;


• se "i" è maggiore di "n" si salta al "end" finale, altrimenti si esegue la "Lista_Comandi";
• si torna all'inizio del ciclo e si incrementa "i" che quindi prende il valore 2;
• se "i" è maggiore di "n" si salta al "end" finale, altrimenti si esegue la "Lista_Comandi";
• si torna all'inizio del ciclo e si incrementa "i" che quindi prende il valore 3;
• etc etc etc

Si eseguono n iterazioni, concludendo il comando quando "i" prende il valore n+1 e quindi si salta al "end"
finale.

E' possibile anche variare ad ogni iterazione l'indice "i" di un valore diverso da 1. Ad esempio il seguente
ciclo for incrementa ogni volta l'indice "i" di un valore 5:

for i=1:5:n
Lista_Comandi;
end

mentre il seguente "ciclo for" decrementa l'indice "i" di uno procedendo con una sorta di "conto alla rovescia":

2
for i=n:-1:1
Lista_Comandi;
end

Vediamo di seguito alcuni esempi:

for i=2:4 % per i che va da 2 a 4


p=2*i % p prende 2*i
end

p = 4
p = 6
p = 8

for i=1:3:8 % per i che va da 1 ad 8 a passo di 3


p=10+i % p prende 10+i
end

p = 11
p = 14
p = 17

for i=6:-1:4 % per i che va da 6 a 4 a passo di -1


p=i/2 % p prende i/2
end

p = 3
p = 2.5000
p = 2

Da quanto detto, il numero di iterazioni che vengono eseguite da un "ciclo for" sono determinate a priori. In
realtà è possibile modificare il flusso dei comandi di un ciclo iterativo tramite i comandi "continue" e "break".

for i=1:n
Lista_Comandi_1;
if condizione_vero/falso
continue
end
Lista_Comandi_2;
end

Il comando "continue" chiude anticipatamente l'iterazione corrente andando direttamente alla iterazione
successiva. Nelle iterazioni del comando precedente si esegue prima la "Lista_Comandi_1", si valuta poi la
"condizione_vero/falso", se tale condizione è falsa si esegue la "Lista_Comandi_2", se invece tale condizione
è vera si salta la "Lista_Comandi_2" e si va direttamente alla iterazione successiva. Ne consegue che la
"Lista_Comandi_1" viene eseguita "n" volte, la "Lista_Comandi_2" viene eseguita solamente le volte in cui la
"condizione_vero/falso" è falsa.

for i=1:n
Lista_Comandi_1;
if condizione_vero/falso
break
end

3
Lista_Comandi_2;
end

Il comando "break" chiude anticipatamente l'intero "ciclo for" andando direttamente dopo al "end" finale. Nelle
iterazioni del comando precedente si esegue prima la "Lista_Comandi_1", si valuta poi la "condizione_vero/
falso", se tale condizione è falsa si esegue la "Lista_Comandi_2", se invece tale condizione è vera si
interrompe istantaneamente il "ciclo for" andando al comando successivo al "end" finale.

Vediamo di seguito alcuni esempi:

for i=2:4 % per i che va da 2 a 4


p=2*i % p prende 2*i
if i==3 % se i coincide con 3
continue % salta alla iterazione successiva
end
p=20+i % p prende 20+i
end

p = 4
p = 22
p = 6
p = 8
p = 24

for i=2:4 % per i che va da 2 a 4


p=2*i % p prende 2*i
if i==3 % se i coincide con 3
break % interrompi l'intero ciclo for
end
p=20+i % p prende 20+i
end

p = 4
p = 22
p = 6

Ciclo Iterativo "while"


Caratteristica peculiare del ciclo iterativo "for" è quella di dover svolgere un numero di iterazioni definito a
priori (con il comando "break" si possono diminuire tali iterazioni, ma non possono essere aumentate). Ci
sono invece situazioni in cui non si può prevedere a priori il numero di iterazioni da svolgere. In questi casi
il ciclo "for" non può essere utilizzato ma si può utilizzare il ciclo iterativo "while". Ad esempio il seguente
comando:

while condizione_vero/falso
Lista_Comandi;
end

continua ad eseguire "Lista_Comandi" fintanto che la "condizione_vero/falso" è vera. Nello specifico accade
quanto segue:

• si verifica la "condizione_vero/falso";
• se è vera si esegue la "Lista_Comandi", altrimenti si salta al "end" finale;

4
• si torna all'inizio del ciclo;

Si osservi come non si sappia quante iterazioni verranno eseguite, il comando sarà concluso solamente
quando la "condizione_vero/falso" diventerà falsa. In particolare, un ciclo iterativo "while" potrebbe anche
svolgere infiniti cicli e diventare quindi un "ciclo infinito"; in questo caso il computer continua a lavorare fino a
che non viene privato di energia elettrica, oppure fino a che non vengono premuti conteporaneamente e per
alcuni secondi i tasti "ctrl" e "C".

Si osservi come un ciclo "for" possa essere facilmente scritto sotto forma di ciclo "while":

% il seguente ciclo "for"


for i=1:n
Lista_Comandi;
end

% è equivalente a
i=1;
while i<=n
Lista_Comandi;
i=i+1;
end

Con qualche abuso computazionale anche un ciclo "while" si può riscrivere tramite un ciclo "for":

% il seguente ciclo "while"


while condizione_vero/falso
Lista_Comandi;
end

% è equivalente a
for i=1:+inf
if condizione_vero/falso
Lista_Comandi;
else
break;
end
end

Come si osserva facilmente, i due cicli iterativi hanno ciascuno le proprie peculiarità e quindi non è opportuno
utilizzare l'uno in termini dell'altro. vediamo di seguito un semplice esempio:

p=1; % si inizializza ad 1 la variabile p


while p<20 % fino a che p<20
p=2*p % p prende il doppio di p
end

p = 2
p = 4
p = 8
p = 16
p = 32

Come si vede facilmente, la prima volta che "p" supera 20 si esce dal ciclo.

5
Come già si è mostrato con il ciclo "for", all'interno di un ciclo "while" si possono inserire salti condizionati,
altri cicli, oltre ai comandi "continue" e "break".

Functions e Subfunctions
Molti sono i comandi MATLAB che siamo abituati ad utilizzare, come ad esempio "size()", "length()", "zeros()"
etc etc. Ciascuno di questi comandi ha la proprietà di ricevere dei parametri in ingresso, detti inputs, e di
restituire dei risultati in uscita, detti outputs.

Per utilizzare efficientemente MATLAB talvolta si ha la necessità di definire dei nuovi comandi personalizzati
e scritti ad hoc per svolgere determinate funzioni. A tal fine si devono definire delle "functions", ovvero
costrutti aventi ad esempio una struttura del tipo seguente:

function [output1,output2]=NomeFunction(input1,input2)
Lista_Comandi;
end

Una function può avere uno, nessuno, o più input, e può essere scritta in modo tale da restituire uno,
nessuno o più output. Ad esempio:

function NomeFunction(input1,input2,input3) % nessun output, 3 inputs


Lista_Comandi;
end

function output=NomeFunction(input) % 1 output, 1 input


Lista_Comandi;
end

function [output1,output2,output3]=NomeFunction() % 3 outputs, nessun input


Lista_Comandi;
end

Una function, per poter diventare un nuovo comando sempre disponibile, deve essere scritta in un m-file
(ovvero in uno script) ed essere salvata nella "Current Folder". Il nome dell'm-file deve essere lo stesso della
function, in caso contrario MATLAB presenta un "warning" per avvertire della possibilità che l'utente possa
eseguire errroneamente una function al posto di un'altra. Ad esempio la seguente function:

function y=Doppio(x)
y=2*x;
end

deve essere redatta in uno script e salvata nella "Current Folder" in un m-file dal nome "Doppio.m". Il nuovo
"comando" può quindi essere invocato facilmente come tutti gli altri comandi MATLAB predefiniti:

Doppio(4)

ans = 8

c=Doppio(2)

c = 4

6
Quando si invoca il comando "Doppio(2)" MATLAB cerca nella "Current Folder" un file denominato
"Doppio.m", passa il valore 2 all'input, esegue i comandi presenti nel corpo della function, e restituisce
l'output. Da questa descrizione si capisce chiaramente (per evitare errori grossolani) sia l'opportunità di
chiamare l'm-file con lo stesso nome della function sia l'opportunità di scrivere una sola function in ogni
singolo m-file.

Vediamo un altro semplice esempio:

function euro=Conversione(Valuta,Cambio)
% conversione(Valuta,Cambio) calcola la quantità di euro equivalenti
% alla quantità di valuta straniera "Valuta" al cambio corrente "Cambio"

% ad esempio cambio euro/dollaro al 15/03/2015 : 1.0593


% 100 USD = 94.40 EUR - 105.93 USD = 100 EUR

euro=Valuta/Cambio;

end

Una volta salvata questa function nel file "Conversione.m" la si può utilizzare con i seguenti comandi:

USD=100

USD = 100

TassoCambio=1.0593

TassoCambio = 1.0593

EUR=Conversione(USD,TassoCambio)

EUR = 94.4020

Si osservi come i nomi utilizzati dalla function al proprio interno per gli inputs e gli outputs siano diversi da
quelli utilizzati al suo esterno, ovvero nel presente Live Script, per invocarla.

Le variabili usate dalla function al proprio interno sono chiamate "variabili locali" e non sono visibili/
utilizzabili al suo esterno dal momento che non vengono a far parte del "Workspace".

Quando MATLAB esegue il seguente comando:

EUR=Conversione(USD,TassoCambio)

le variabili "USD" e "TassoCambio" vengono prese dal "Workspace", trasformate in valori e passate ai
due inputs della function "Conversione.m". A questo punto l'esecuzione passa alla function, che riceve i
due valori in input e li assegna alle proprie due variabili locali "Valuta" e "Cambio", calcola il valore in euro
assegnandolo alla variabile locale "euro" che poi restituisce come output, tale output viene trasformato in un
valore e restituito come risultato del lavoro della function. La function, una volta terminato il proprio lavoro
viene abbandonata, l'esecuzione dei comandi torna quindi al comando iniziale, il valore fornito dalla function
come risultato viene assegnato alla variabile "EUR" che entra a far parte del "Workspace". Si osservi che
le variabili "Valuta", "Cambio" ed "euro" non compaiono mai nel "Workspace", ovvero esistono in modo

7
trasparente solo durante l'esecuzione della function e svaniscono quando la function ha terminato il proprio
lavoro.

Si osservi infine che per semplificare la scrittura del codice talvolta anche all'interno di una function potrebbe
servire un comando specifico da definire ex-novo. Se tale nuova function è di utilità generale conviene
scriverla in un nuovo m-file, se invece è specifica della function principale si può scrivere direttamente al suo
interno:

function [output1,output2]=FunctionMadre(input1,input2)
Lista_Comandi_Madre;

function out=FunctionFiglia(in)
Lista_Comandi_Figlia
end

end

Nell'esempio precedente la "FunctionFiglia()" è utilizzabile solamente dalla "FunctionMadre()". Si osservi che


la "FunctionFiglia()" può utilizzare tutte le variabili della "FunctionMadre()". La "FunctionMadre()" invece non
vede le variabili locali della "FunctionFiglia()", alla quale può solamente chiedere di calcolare un output sulla
base degli input passati.

8
Salti Condizionati e Cicli Iterativi - Esempi Vari
(Live Script realizzato con MATLAB versione 2018a)

clear % si svuota preliminarmente il Workspace di MATLAB per evitare problemi

Per poter svolgere gli esercizi successivi è opportuno avere dei dati nel Workspace da poter utilizzare. A tal
fine, definiamo il seguente vettore v, la seguente matrice A e calcoliamone le dimensioni:

v=[1 2 -1 -3 2 -1 0 4 0 3 -2 4 0 -2 0]

v = 1×15
1 2 -1 -3 2 -1 0 4 0 3 -2 4 0

n=length(v)

n = 15

A=[1 2 -1 -3 0; 2 -1 0 1 4; 0 -1 3 -2 2; 0 -2 0 -1 3]

A = 4×5
1 2 -1 -3 0
2 -1 0 1 4
0 -1 3 -2 2
0 -2 0 -1 3

[rA,cA]=size(A)

rA = 4
cA = 5

Contatori
Spesso ci si trova a dover contare il numero di volte in cui viene verificata una certa proprietà; si potrebbe
voler contare il numero di monete da due euro che abbiamo in tasca, si potrebbero voler contare il numero
dei flussi di cassa positivi che abbiamo avuto a bilancio. Ad esempio, supponiamo di volerne determinare il
numero degli elementi positivi contenuti nel vettore v. A tal fine due sono i compiti che devono essere svolti:

• occorre visitare ogni singola componente del vettore, dalla prima all'ultima;
• nel caso in cui la componente sia positiva occorre tenerne di conto e "contarla".

Per visitare l'intero vettore occorre un ciclo "for", con la variabile indice del ciclo che passa dal valore 1 al
valore n. Per verificare se la singola componente del vettore è positiva occorre un comando "if". Per contare
i valori positivi occorre una variabile, detta contatore, che viene incrementata ogni volta che si incontra
un valore positivo; ovviamente, la variabile contatore deve essere inizializzata a zero per poter contare
correttamente. Il codice risulta quindi essere:

numpos=0; % si inizializza il contatore numpos a zero


for i=1:n % si scorrono tutte le componenti del vettore
if v(i)>0 % si verifica se la singola componente è positiva

1
numpos=numpos+1; % in tal caso si incrementa il contatore numpos
end
end
numpos % vediamo quante sono le componenti positive

numpos = 6

Utilizzando anche le opzioni "elseif" ed "else" del salto condizionato "if" è possibile utilizzare anche più
contatori contemporaneamente. Ad esempio, proviamo a contare anche il numero delle componenti negative
e di quelle nulle:

numpos=0; % si inizializza il contatore numpos a zero


numneg=0; % si inizializza il contatore numneg a zero
numzero=0; % si inizializza il contatore numzero a zero
for i=1:n % si scorrono tutte le componenti del vettore
if v(i)>0 % si verifica se la singola componente è positiva
numpos=numpos+1; % in tal caso si incrementa il contatore numpos
elseif v(i)<0 % si verifica se la singola componente è negativa
numneg=numneg+1; % in tal caso si incrementa il contatore numneg
else % in caso contrario la componente è nulla
numzero=numzero+1; % e quindi si incrementa il contatore numzero
end
end
numpos % vediamo quante sono le componenti positive

numpos = 6

numneg % vediamo quante sono le componenti negative

numneg = 5

numzero % vediamo quante sono le componenti nulle

numzero = 4

E' possibile utilizzare i contatori anche per analizzare una matrice, ad esempio per contare il numero di
elementi positivi e negativi in ogni singola riga, colonna, o in tutta la matrice. Iniziamo a contare positivi e
negativi in ogni singola riga:

numpos=zeros(rA,1); % si inizializza numpos a zero per ogni riga


numneg=zeros(rA,1); % si inizializza numneg a zero per ogni riga
for i=1:rA % si scorrono tutte le righe
for j=1:cA % si scorrono tutte le colonne
if A(i,j)>0 % si verifica se la singola componente è positiva
numpos(i)=numpos(i)+1; % e si incrementa il contatore numpos della riga i
elseif A(i,j)<0 % si verifica se la singola componente è negativa
numneg(i)=numneg(i)+1; % e si incrementa il contatore numneg della riga i
end
end
end
numpos' % vediamo quante sono le componenti positive

2
ans = 1×4
2 3 2 1

numneg' % vediamo quante sono le componenti negative

ans = 1×4
2 1 2 2

Contiamo adesso positivi e negativi in ogni singola colonna:

numpos=zeros(1,cA); % si inizializza numpos a zero per ogni colonna


numneg=zeros(1,cA); % si inizializza numneg a zero per ogni colonna
for j=1:cA % si scorrono tutte le colonne
for i=1:rA % si scorrono tutte le righe
if A(i,j)>0 % si verifica se la singola componente è positiva
numpos(j)=numpos(j)+1; % e si incrementa il contatore numpos della colonna j
elseif A(i,j)<0 % si verifica se la singola componente è negativa
numneg(j)=numneg(j)+1; % e si incrementa il contatore numneg della colonna j
end
end
end
numpos % vediamo quante sono le componenti positive

numpos = 1×5
2 1 1 1 3

numneg % vediamo quante sono le componenti negative

numneg = 1×5
0 3 1 3 0

Contiamo infine positivi e negativi di tutta la matrice:

numpos=0; % si inizializza un contatore numpos a zero


numneg=0; % si inizializza un contatore numneg a zero
for i=1:rA % si scorrono tutte le righe
for j=1:cA % si scorrono tutte le colonne
if A(i,j)>0 % si verifica se la singola componente è positiva
numpos=numpos+1; % in tal caso si incrementa il contatore numpos
elseif A(i,j)<0 % si verifica se la singola componente è negativa
numneg=numneg+1; % in tal caso si incrementa il contatore numneg
end
end
end
numpos % vediamo quante sono le componenti positive

numpos = 8

numneg % vediamo quante sono le componenti negative

numneg = 7

3
Accumulatori
Altra necessità estremamente comune è quella di dover sommare tra loro alcuni valori; sommare il valore
delle banconote presenti nel portafoglio per sapere quanti soldi si hanno, sommare il valore dei flussi di
cassa positivi per conoscere l'ammontare complessivo delle entrate a bilancio. Ad esempio, supponiamo di
voler sommare tra loro gli elementi positivi contenuti nel vettore v. A tal fine due sono i compiti che devono
essere svolti:

• occorre visitare ogni singola componente del vettore, dalla prima all'ultima;
• nel caso in cui la componente sia positiva occorre sommarne il valore alla somma parziale.

Per visitare l'intero vettore occorre un ciclo "for", con la variabile indice del ciclo che passa dal valore 1
al valore n. Per verificare se la singola componente del vettore è positiva occorre un comando "if". Per
sommare tra loro i valori positivi occorre una variabile, detta accumulatore, che ogni volta che si incontra
un valore positivo viene aumentata di tale valore; ovviamente, la variabile accumulatore deve essere
inizializzata a zero per poter sommare correttamente. Il codice risulta quindi essere:

valpos=0; % si inizializza l'accumulatore valpos a zero


for i=1:n % si scorrono tutte le componenti del vettore
if v(i)>0 % si verifica se la singola componente è positiva
valpos=valpos+v(i); % in tal caso si aumenta l'accumulatore valpos del valore v(i)
end
end
valpos % vediamo quanto è la somma delle componenti positive di v

valpos = 16

Utilizzando anche l'opzioni "elseif" del salto condizionato "if" è possibile utilizzare anche più accumulatori
contemporaneamente. Ad esempio, proviamo a sommare tra loro anche le componenti negative di v:

valpos=0; % si inizializza l'accumulatore valpos a zero


valneg=0; % si inizializza l'accumulatore valneg a zero
for i=1:n % si scorrono tutte le componenti del vettore
if v(i)>0 % si verifica se la singola componente è positiva
valpos=valpos+v(i); % in tal caso si aumenta l'accumulatore valpos del valore v(i)
elseif v(i)<0 % si verifica se la singola componente è negativa
valneg=valneg+v(i); % in tal caso si aumenta l'accumulatore valneg del valore v(i)
end
end
valpos % vediamo quanto è la somma delle componenti positive di v

valpos = 16

valneg % vediamo quanto è la somma delle componenti negative di v

valneg = -9

Si osservi come la differenza tra contatori e accumulatori sia che nei primi si aumenta la variabile di 1 mentre
nei secondi si aumenta la variabile del valore "v(i)".

4
Anche in questo caso è possibile utilizzare gli accumulatori per analizzare una matrice, ad esempio per
sommare il numero di elementi positivi e negativi in ogni singola riga, colonna, o in tutta la matrice. Iniziamo
a sommare positivi e negativi in ogni singola riga:

valpos=zeros(rA,1); % si inizializza valpos a zero per ogni riga


valneg=zeros(rA,1); % si inizializza valneg a zero per ogni riga
for i=1:rA % si scorrono tutte le righe
for j=1:cA % si scorrono tutte le colonne
if A(i,j)>0 % si verifica se la singola componente è positiva
valpos(i)=valpos(i)+A(i,j); % e si aumenta l'accumulatore valpos della riga i
elseif A(i,j)<0 % si verifica se la singola componente è negativa
valneg(i)=valneg(i)+A(i,j); % e si aumenta l'accumulatore valneg della riga i
end
end
end
valpos' % vediamo quanto è la somma delle componenti positive

ans = 1×4
3 7 5 3

valneg' % vediamo quanto è la somma delle componenti negative

ans = 1×4
-4 -1 -3 -3

Sommiamo adesso positivi e negativi in ogni singola colonna:

valpos=zeros(1,cA); % si inizializza valpos a zero per ogni colonna


valneg=zeros(1,cA); % si inizializza valneg a zero per ogni colonna
for j=1:cA % si scorrono tutte le colonne
for i=1:rA % si scorrono tutte le righe
if A(i,j)>0 % si verifica se la singola componente è positiva
valpos(j)=valpos(j)+A(i,j); % e si aumenta l'accumulatore valpos della colonna j
elseif A(i,j)<0 % si verifica se la singola componente è negativa
valneg(j)=valneg(j)+A(i,j); % e si aumenta l'accumulatore valneg della colonna j
end
end
end
valpos % vediamo quanto è la somma delle componenti positive

valpos = 1×5
3 2 3 1 9

valneg % vediamo quanto è la somma delle componenti negative

valneg = 1×5
0 -4 -1 -6 0

Contiamo infine positivi e negativi di tutta la matrice:

valpos=0; % si inizializza un accumulatore valpos a zero


valneg=0; % si inizializza un accumulatore valneg a zero
for i=1:rA % si scorrono tutte le righe

5
for j=1:cA % si scorrono tutte le colonne
if A(i,j)>0 % si verifica se la singola componente è positiva
valpos=valpos+A(i,j); % in tal caso si aumenta l'accumulatore valpos
elseif A(i,j)<0 % si verifica se la singola componente è negativa
valneg=valneg+A(i,j); % in tal caso si aumenta l'accumulatore valneg
end
end
end
valpos % vediamo quanto è la somma delle componenti positive

valpos = 18

valneg % vediamo quanto è la somma delle componenti negative

valneg = -11

Determinazione del Massimo e del Minimo Valore in un Vettore


Altra problematica classica è quella di determinare il massimo ed il minimo degli elementi di un vettore. Ad
esempio, supponiamo di voler la massima e la minima componente del vettore v. A tal fine due sono i compiti
che devono essere svolti:

• occorre visitare ogni singola componente del vettore, dalla prima all'ultima;
• occorre memorizzare il massimo/minimo valore temporaneo corrente;
• se si trova un valore migliore (più grande o più piccolo del massimo/minimo valore temporaneo
corrente) si aggiorna l'ottimo temporaneo.

Per visitare l'intero vettore occorre un ciclo "for", con la variabile indice del ciclo che passa dal valore 1 al
valore n. Per verificare se la singola componente del vettore è migliore del massimo/minimo temporaneo
occorre un comando "if". Una prima possibile implementazione potrebbe essere la seguente:

valmax=v(1); % prendiamo il primo elemento come valore massimo temporaneo


for i=2:n % si scorrono tutte le altre componenti del vettore
if v(i)>valmax % se si trova un valore più grande
valmax=v(i); % lo si prende come nuovo valore massimo temporaneo
end
end
valmin=v(1); % prendiamo il primo elemento come valore minimo temporaneo
for i=2:n % si scorrono tutte le altre componenti del vettore
if v(i)<valmin % se si trova un valore più piccolo
valmin=v(i); % lo si prende come nuovo valore minimo temporaneo
end
end
[valmin valmax]

ans = 1×2
-3 4

Si osservi che con questa implementazione si scorre inutilmente il vettore v per due volte. In effetti, la ricerca
del massimo ed il minimo valore poteva essere condotta contemporaneamente:

valmax=v(1); % prendiamo il primo elemento come valore massimo temporaneo


6
valmin=v(1); % prendiamo il primo elemento come valore minimo temporaneo
for i=2:n % si scorrono tutte le altre componenti del vettore
if v(i)>valmax % se si trova un valore più grande
valmax=v(i); % lo si prende come nuovo valore massimo temporaneo
end
if v(i)<valmin % se si trova un valore più piccolo
valmin=v(i); % lo si prende come nuovo valore minimo temporaneo
end
end
[valmin valmax]

ans = 1×2
-3 4

Anche questa nuova implementazione può essere migliorata, infatti nel caso in cui sia "v(i)>valmax" è
assolutamente inutile controllare anche se "v(i)<valmin" poiché essendo valmin<=valmax tale condizione
logica è sicuramente falsa. Il codice pertanto si può ulteriormente semplificare utilizzando l'opzione "elseif":

valmax=v(1); % prendiamo il primo elemento come valore massimo temporaneo


valmin=v(1); % prendiamo il primo elemento come valore minimo temporaneo
for i=2:n % si scorrono tutte le altre componenti del vettore
if v(i)>valmax % se si trova un valore più grande
valmax=v(i); % lo si prende come nuovo valore massimo temporaneo
elseif v(i)<valmin % altrimenti, se si trova un valore più piccolo
valmin=v(i); % lo si prende come nuovo valore minimo temporaneo
end
end
[valmin valmax]

ans = 1×2
-3 4

A titolo di esempio, una semplicissima function/subfunction che determina la minima e la massima


componente di un vettore è la seguente:

function [valmin,valmax]=MinMax(v)
valmin=v(1);
valmax=v(1);
for h=2:length(v)
if v(h)>valmax
valmax=v(h);
elseif v(h)<valmin
valmin=v(h);
end
end
end

Questa function, salvata in un opportuno m-file, può essere ad esempio invocata con il seguente comando:

[valmin,valmax]=MinMax(v)

valmin = -3
valmax = 4

7
Si tenga inoltre conto che molto spesso non solo è necessario conoscere i valori massimo e minimo, ma
anche la loro posizione (supponendo sia unica) nel vettore. Per implementare tale ulteriore esigenza le
modifiche da apportare al codice sono minime:

valmax=v(1); % prendiamo il primo elemento come valore massimo temporaneo


posmax=1; % e se ne memorizza la posizione 1
valmin=v(1); % prendiamo il primo elemento come valore minimo temporaneo
posmin=1; % e se ne memorizza la posizione 1
for i=2:n % scorriamo le altre componenti del vettore
if v(i)>valmax % se si trova un valore più grande
valmax=v(i); % lo si prende come nuovo valore massimo temporaneo
posmax=i; % e se ne memorizza la posizione i
elseif v(i)<valmin % altrimenti se si trova un valore più piccolo
valmin=v(i); % lo si prende come nuovo valore minimo temporaneo
posmin=i; % e se ne memorizza la posizione i
end
end
[valmin valmax]

ans = 1×2
-3 4

[posmin posmax]

ans = 1×2
4 8

Ulteriore esigenza, che capita spessissimo quando si lavora con vettori molto lunghi, è quella di voler trovare
i valori massimo e minimo non di tutto il vettore ma di una sua porzione. Supponiamo, ad esempio, di dover
trovare la massima ed la minima componente del vettore v comprese tra la posizione pstart e la posizione
pend, con 1<=pstart<pend<=n. Il codice risulta:

pstart=6;
pend=11;
valmax=v(pstart); % prendiamo l'elemento in posizione pstart come valore max temp.
posmax=pstart; % e se ne memorizza la posizione pstart
valmin=v(pstart); % prendiamo l'elemento in posizione pstart come valore min temp.
posmin=pstart; % e se ne memorizza la posizione pstart
for i=(pstart+1):pend % scorriamo le altre componenti del vettore, da pstart+1 a pend
if v(i)>valmax % se si trova un valore più grande
valmax=v(i); % lo si prende come nuovo valore massimo temporaneo
posmax=i; % e se ne memorizza la posizione i
elseif v(i)<valmin % altrimenti se si trova un valore più piccolo
valmin=v(i); % lo si prende come nuovo valore minimo temporaneo
posmin=i; % e se ne memorizza la posizione i
end
end
[valmin valmax]

ans = 1×2
-2 4

8
[posmin posmax]

ans = 1×2
11 8

Questo codice è facilmente implementabile anche in una function o subfunction(in cui per brevità si assume
sia 1<=pstart<pend<=length(v)):

function [valmin,valmax,posmin,posmax]=MinMaxPos(v,pstart,pend)
valmin=v(pstart);
posmin=pstart;
valmax=v(pstart);
posmax=pstart;
for h=(pstart+1):pend
if v(h)>valmax
valmax=v(h);
posmax=h;
elseif v(h)<valmin
valmin=v(h);
posmin=h;
end
end
end

La precedente function, salvata in un opportuno m-file, può essere ad esempio invocata con il seguente
comando:

[valmin,valmax,posmin,posmax]=MinMaxPos(v,6,11)

valmin = -2
valmax = 4
posmin = 11
posmax = 8

Determinazione Massimi e Minimi Valori in un Array


Per analizzare massimi e minimi valori di una matrice si procede in modo analogo. Determiniamo massimi e
minimi valori in ogni singola riga:

valmax=A(:,1); % si prende la prima colonna come valori max temp.


posmax=ones(rA,1); % e si memorizza la posizione 1 per ogni riga
valmin=A(:,1); % si prende la prima colonna come valori min temp.
posmin=ones(rA,1); % e si memorizza la posizione 1 per ogni riga
for i=1:rA % scorriamo tutte le righe
for j=2:cA % scorriamo le colonne dalla 2 alla cA
if A(i,j)>valmax(i) % se si trova per la riga i un valore più grande
valmax(i)=A(i,j); % lo si prende come nuovo valore massimo temporaneo
posmax(i)=j; % e si memorizza la colonna j per la riga i
elseif A(i,j)<valmin(i) % altrimenti se si trova un valore più piccolo
valmin(i)=A(i,j); % lo si prende come nuovo valore minimo temporaneo
posmin(i)=j; % e si memorizza la colonna j per la riga i
end
end

9
end
valmax'

ans = 1×4
2 4 3 3

posmax'

ans = 1×4
2 5 3 5

valmin'

ans = 1×4
-3 -1 -2 -2

posmin'

ans = 1×4
4 2 4 2

Determiniamo poi massimi e minimi valori in ogni singola colonna:

valmax=A(1,:); % si prende la prima riga come valori max temp.


posmax=ones(1,cA); % e si memorizza la posizione 1 per ogni colonna
valmin=A(1,:); % si prende la prima riga come valori min temp.
posmin=ones(1,cA); % e si memorizza la posizione 1 per ogni colonna
for j=1:cA % scorriamo tutte le colonne
for i=2:rA % scorriamo le righe dalla 2 alla cA
if A(i,j)>valmax(j) % se si trova per la colonna j un valore più grande
valmax(j)=A(i,j); % lo si prende come nuovo valore massimo temporaneo
posmax(j)=i; % e si memorizza la riga i per la colonna j
elseif A(i,j)<valmin(j) % altrimenti se si trova un valore più piccolo
valmin(j)=A(i,j); % lo si prende come nuovo valore minimo temporaneo
posmin(j)=i; % e si memorizza la riga i per la colonna j
end
end
end
valmax

valmax = 1×5
2 2 3 1 4

posmax

posmax = 1×5
2 1 3 2 2

valmin

valmin = 1×5
0 -2 -1 -3 0

posmin

10
posmin = 1×5
3 4 1 1 1

Infine, determiniamo massimo e minimo valore di tutta la matrice. In questo caso, per memorizzare la
posizione dobbiamo tener conto sia della riga sia della colonna.

valmax=A(1,1); % si prende A(1,1) come valore max temp.


rigamax=1; % si memorizza la riga 1
colmax=1; % e la colonna 1
valmin=A(1,1); % si prende la prima colonna come valori min temp.
rigamin=1; % si memorizza la riga 1
colmin=1; % e la colonna 1
for i=1:rA % scorriamo tutte le righe
for j=2:cA % scorriamo tutte le colonne
if A(i,j)>valmax % se si trova per l'elemento (i,j) un valore più grande
valmax=A(i,j); % lo si prende come nuovo valore massimo temporaneo
rigamax=i; % e si memorizza la riga i
colmax=j; % e la colonna j
elseif A(i,j)<valmin % altrimenti se si trova un valore più piccolo
valmin=A(i,j); % lo si prende come nuovo valore minimo temporaneo
rigamin=i; % e si memorizza la riga i
colmin=j; % e la colonna j
end
end
end
valmax

valmax = 4

[rigamax colmax]

ans = 1×2
2 5

valmin

valmin = -3

[rigamin colmin]

ans = 1×2
1 4

Flag
Con il termine "flag" si intendono delle variabili "vero/falso" che indicano se una certa proprietà è o meno
verificata. Ad esempio si potrebbe voler sapere se il vettore "v" ha o meno almeno una componente positiva:

pospresente=false; % si inizializza la variabile flag a "falso"


for i=1:n % si scorre tutto il vettore
if v(i)>0 % si controlla se la componente è positiva
pospresente=true; % nel qual caso la variabile flag prende "vero"
11
break % si può interrompere la visita di v
end
end
pospresente

pospresente = logical
1

La variabile flag "pospresente" si comporta un pò come la bandierina dei guardalinee di una partita di calcio,
viene tenuta rivolta verso il basso (valore "false", ovvero non abbiamo ancora trovato alcuna componente
positiva) ed alzata solo in caso di infrazioni di gioco (valore "true", una componente positiva è stata trovata).

Si osservi come la variabile flag debba necessariamente essere inizializzata a "false"; nel ciclo "for" infatti
si può solo riconoscere la presenza di valori positivi ed assegnare alla variabile flag il valore "true", nessun
valore viene invece assegnato nel caso in cui il vettore non abbia alcun valore positivo.

Liste e Maschere
In molte situazioni ci si trova a dover determinare l'elenco delle componenti di un vettore che verificano una
certa proprietà. Ad esempio, l'elenco delle componenti positive, delle componenti negative, dei massimi
o minimi valori nel caso in cui essi non siano unici. Le componenti del vettore che verificano la proprietà
richiesta possono essere espresse in due modi diversi:

• tramite una lista, ovvero un elenco delle componenti che verificano la proprietà richiesta
• tramite una maschera, ovvero un vettore di valori logici vero/falso che indicano se la singola
componente verifica o meno la proprietà richiesta (sostanzialmente un vettore di variabili flag)

Si osservi che la lista non ha una lunghezza predefinita a priori, può essere anche una lista vuota (nessun
elemento verifica la proprietà) ed al massimo è lunga tanto quanto il vettore stesso (tutti gli elementi
verificano la proprietà). Una maschera invece ha sempre la stessa lunghezza del vettore, in quanto ogni
sua componente deve indicare se la corrispondente componente del vettore verifica o meno la proprietà
richiesta.

A titolo di esempio vediamo di individuare tutte le componenti negative del vettore v. Determiniamo prima la
lista:

ListaNeg=zeros(1,n); % inizializziamo la lista alla dimensione massima


numelem=0; % inizializziamo a 0 il numero di elementi nella lista
for i=1:n % si scorre tutto il vettore
if v(i)<0 % si controlla se la componente è negativa
numelem=numelem+1; % si incrementa il numero di elementi nella lista
ListaNeg(numelem)=i; % nella posizione numelem si mette la componente i
end
end
ListaNeg=ListaNeg(1:numelem); % alla fine si tolgono dalla lista gli elementi non usati
ListaNeg

ListaNeg = 1×5
3 4 6 11 14

e poi la maschera:

12
MaskNeg=false(1,n); % si inizializza la maschera con tutti valori "false"
for i=1:n % si scorre tutto il vettore
if v(i)<0 % si controlla se la componente è negativa
MaskNeg(i)=true; % in tal caso nella maschera si mette il valore "true"
end
end
MaskNeg

MaskNeg = 1×15 logical array


0 0 1 1 0 1 0 0 0 0 1 0 0 1 0

Se si lavora con le matrici, le maschere sono a loro volta matrici. Ad esempio la maschera degli elementi
negativi della matrice A risulta:

MaskNeg=false(rA,cA);
for i=1:rA
for j=1:cA
if A(i,j)<0
MaskNeg(i,j)=true;
end
end
end
MaskNeg

MaskNeg = 4×5 logical array


0 0 1 1 0
0 1 0 0 0
0 1 0 1 0
0 1 0 1 0

la lista stavolta diventa una sequenza di coppie ordinate, quindi una matrice con due righe, in quanto si
devono memorizzare sia le righe sia le colonne degli elementi negativi.

ListaNeg=zeros(2,rA*cA); % inizializziamo la lista alla dimensione massima


numelem=0; % inizializziamo a 0 il numero di elementi in lista
for i=1:rA % si scorrono tutte le righe
for j=1:cA % si scorrono tutte le colonne
if A(i,j)<0 % si controlla se la componente è negativa
numelem=numelem+1; % si incrementa il numero di elementi nella lista
ListaNeg(:,numelem)=[i;j]; % nella colonna numelem della lista si mettono (i,j)
end
end
end
ListaNeg=ListaNeg(:,1:numelem); % si tolgono dalla lista gli elementi non usati
ListaNeg

ListaNeg = 2×7
1 1 2 3 3 4 4
3 4 2 2 4 2 4

Metodo di Bisezione

13
Il metodo di bisezione è sicuramente il più semplice algoritmo per determinare gli zeri o le soluzioni di una
equazione.

Si consideri una equazione del tipo , supponiamo che la funzione sia continua e che esistano
due valori a e b tali per cui .

Per la continuità della funzione ed il "Teorema degli Zeri" esiste almeno un valore tale per cui . Il
problema è che raramente è possibile determinare analiticamente la soluzione di una equazione nonlineare;
in questi casi occorre quindi un algoritmo che permetta di fornire una approssimazione di . L'idea
dell'algoritmo è molto semplice:


con il valore si divide in due parti uguali l'intervallo
• si calcola il valore
• si prende come nuovo intervallo di
riferimento se oppure se
• si ripete il procedimento fino a che l'intervallo ottenuto non diventa sufficientemente piccolo

Per implementare il metodo di bisezione occorre utilizzare un ciclo iterativo "while", in quanto il numero di
iterazioni da eseguire non è a priori determinato.

A titolo di esempio, cerchiamo uno zero della funzione nell'intervallo con una
precisione di 7 cifre decimali.

A tal fine, definiamo preliminarmente la funzione, gli estremi dell'intervallo e la precisione richiesta.

f=@(x) x^2-exp(x)+2; % definizione della funzione


a=0; % definizione di a
b=2; % definizione di b
precis=10^(-7); % definizione della precisione
f(a)*f(b) % verifica che sia f(a)*f(b)<0

ans = -1.3891

Vediamo adesso di implementare il metodo di bisezione:

fa=f(a); % si carica in memoria il valore f(a)


fb=f(b); % si carica in memoria il valore f(b)
while (b-a)>precis % si controlla se si è raggiunta la precisione richiesta
c=(a+b)/2; % si calcola il punto medio
fc=f(c); % si carica in memoria il valore f(c)
if fc==0 % se f(c) è nullo allora c è la soluzione
a=c; % si riduce l'intervallo al solo valore c
b=c;
elseif fa*fc<0 % altrimenti, se f(a)*f(c)<0
b=c; % si prende il sottointervallo [a,c]
else % altrimenti, e manca solo il caso f(c)*f(b)<0
a=c; % si prende il sottointervallo [c,b]
end
end
sol=(a+b)/2 % come soluzione approssimata si prende il punto medio di [a,b]

14
sol = 1.3191

f(sol)

ans = 3.2610e-08

Il metodo di bisezione si può facilmente implementare anche con una function/subfunction.

function sol=bisezione(f,xleft,xright,precis)
if not(xl<xr)
error('intervallo non corretto')
end
a=xleft;
b=xright;
fa=f(a);
fb=f(b);
if fa*fb>0
error('Metodo non applicabile')
elseif fa==0
sol=a;
return
elseif fb==0
sol=b;
return
end
while (b-a)>precis
c=(a+b)/2;
fc=f(c);
if fc==0
a=c;
b=c;
elseif fa*fc<0
b=c;
else
a=c;
end
end
sol=(a+b)/2;
end

La precedente function, salvata in un opportuno m-file, può essere ad esempio invocata con il seguente
comando:

sol=bisezione(f,0,2,10^(-7))

sol = 1.3191

f(sol)

ans = 3.2610e-08

15
Salti Condizionati e Cicli Iterativi - Esempi in Analisi Tecnica
Per poter svolgere gli esercizi successivi è opportuno avere dei dati storici nel Workspace. A tal fine
carichiamo preliminarmente il file IBM.csv.

Ibm=readtable('IBM.csv'); % si carica la tabella

Warning: Variable names were modified to make them valid MATLAB identifiers. The original names are saved in
the VariableDescriptions property.

[nday,ncol]=size(Ibm) % determiniamo numero di righe e colonne

nday = 14154
ncol = 7

Ibm([1:4,end-3:end],:) % visualizziamo per controllo alcuni dati

ans = 8×7 table

Date Open High Low Close AdjClose

1 1962-01-02 7.7133 7.7133 7.6267 7.6267 0.6893

2 1962-01-03 7.6267 7.6933 7.6267 7.6933 0.6953

3 1962-01-04 7.6933 7.6933 7.6133 7.6167 0.6884

4 1962-01-05 7.6067 7.6067 7.4533 7.4667 0.6748

5 2018-03-20 157.5200 157.9300 155.2900 156.2000 156.2000

6 2018-03-21 156.5700 158.2000 155.9200 156.6900 156.6900

7 2018-03-22 155.0000 155.2500 152.0000 152.0900 152.0900

8 2018-03-23 152.2500 152.5800 148.5400 148.8900 148.8900

Ordine cronologico dei dati storici


Per poter essere utilizzati, i dati storici disponibili nella tabella devono essere in ordine cronologico crescente,
ovvero dalla più vecchia alla più recente. E' quindi opportuno prima di iniziare a lavorare con essi verificare
che in effetti l'ordine cronologico sia corretto, in caso contrario è bene segnalare l'errore. Questo controllo
preliminare è una applicazione immediata dei cicli "for" e dei salti condizionati "if".

for i=2:nday % scorro le righe dalla seconda per non avere errore con i-1
if not(Ibm.Date(i)>Ibm.Date(i-1)) % verifico il corretto ordine
error('Quotazioni non in ordine cronologico') % se non è corretto si da errorre
end
end

16
Se anche per una sola riga l'ordine non è corretto si ha un errore. Se invece l'ordine delle giornate è corretto
non si restituisce alcun risultato.

Selezione di un periodo temporale specificato


In molti esercizi si devono visualizzare o elaborare i dati storici di un titolo limitatamente ad uno specificato
periodo temporale. In altre parole, non si devono considerare tutte le giornate borsistiche di cui ai dati storici,
bensì solamente un loro sottoinsieme. Di seguito vediamo come individuare le righe della tabella dei dati
storici corrispondenti al periodo temporale specificato.

Ad esempio, vediamo come individuare nella tabella di cui al file IBM.csv le righe relative al periodo
temporale che va da d1 a d2 con:

• d1 : 25 dicembre 1980
• d2 : 1 maggio 1981

Giorni=Ibm.Date; % per comodità selezioniamo la colonna delle date


d1=datetime('25-dec-1980'); % si definisce d1
d2=datetime('1-may-1981'); % si definisce d2
for i=1:nday % si scorrono le date
if Giorni(i)>=d1 % si verifica di aver raggiunto d1
rowd1=i; % abbiamo trovato rowd1
break % appena trovato rowd1 ci si deve fermare
end
end
if d2>=Giorni(nday) % si verifica se la data d2 supera l'ultima data disponibile
rowd2=nday; % in questo caso rowd2 deve prendere l'ultima riga
else % altrimenti
for i=rowd1:nday % si scorrono le date (non serve scorrere quelle prima di rowd1)
if Giorni(i)>d2 % si verifica di aver superato d2
rowd2=i-1; % rowd2 è quindi la riga precedente
break % appena trovato rowd2 ci si deve fermare
end
end
end

Attenzione, nel codice precedente si assume che sia d1<d2 e che le date siano in ordine cronologico
crescente.

Vediamo i risultati ottenuti.

[rowd1 rowd2]

ans = 1×2
4763 4850

[Giorni(rowd1) Giorni(rowd2)]

ans = 1×2 datetime array


1980-12-26 1981-05-01

17
Come si vede, il giorno 25 dicembre 1980 la borsa era chiusa e si è quindi partiti dalla riga corrispondente
alla prima data utile successiva. Il 1 maggio 1981 invece la borsa è risultata aperta.

Il codice precedente può essere efficientemente implementato in una function/subfunction:

function [rowdstart,rowdend]=FindRows(days,dstart,dend)
nday=length(days);
for h=1:nday
if days(h)>=dstart
rowdstart=h;
break
end
end
if dend>=days(nday)
rowdend=nday;
else
for h=rowdstart:nday
if days(h)>dend
rowdend=h-1;
break
end
end
end
end

Salvata la precedente function in un m-file la si potrebbe invocare con il comando seguente:

d1=datetime('25-dec-1980'); % si definisce d1
d2=datetime('1-may-1981'); % si definisce d2
[rowd1,rowd2]=FindRows(Ibm.Date,d1,d2)

rowd1 = 4763
rowd2 = 4850

Determinazione Massimo e Minimo Valore in un Vettore


Per trovare il massimo ed il minimo prezzo di chiusura dei dati storici del titolo Ibm ("MaxVal" e "MinVal")
basta utilizzare i seguenti semplici comandi:

MaxVal=Ibm.Close(1); % prendiamo il primo elemento come valore max temporaneo


MinVal=Ibm.Close(1); % prendiamo il primo elemento come valore min temporaneo
for i=2:nday % si scorrono tutte le altre componenti del vettore
if Ibm.Close(i)>MaxVal % se si trova un valore più grande
MaxVal=Ibm.Close(i); % lo si prende come nuovo valore massimo temporaneo
elseif Ibm.Close(i)<MinVal % altrimenti, se si trova un valore più piccolo
MinVal=Ibm.Close(i); % lo si prende come nuovo valore minimo temporaneo
end
end
[MinVal MaxVal]

ans = 1×2
4.0800 215.8000

18
Si osservi che si poteva anche utilizzare la function "MaxMin()" precedentemente salvata in un m-file:

[MinVal,MaxVal]=MinMax(Ibm.Close)

MinVal = 4.0800
MaxVal = 215.8000

Se invece si è interessati a conoscere in riferimento al periodo temporale [d1,d2] il massimo ed il minimo


prezzo di chiusura oltre alla data in cui si sono avuti tali prezzi occorre utilizzare il seguente codice (si ricordi
che abbiamo già trovato le righe "rowd1" e "rowd2" corrispondenti alle date "d1" e "d2"):

MaxVal=Ibm.Close(rowd1); % prendiamo l'elemento in pos. pstart come valore max temp.


PosMaxVal=rowd1; % e se ne memorizza la posizione pstart
MinVal=Ibm.Close(rowd1); % prendiamo l'elemento in pos. pstart come valore min temp.
PosMinVal=rowd1; % e se ne memorizza la posizione pstart
for i=(rowd1+1):rowd2 % scorriamo le altre componenti, da pstart+1 a pend
if Ibm.Close(i)>MaxVal % se si trova un valore più grande
MaxVal=Ibm.Close(i); % lo si prende come nuovo valore massimo temporaneo
PosMaxVal=i; % e se ne memorizza la posizione i
elseif Ibm.Close(i)<MinVal % altrimenti se si trova un valore più piccolo
MinVal=Ibm.Close(i); % lo si prende come nuovo valore minimo temporaneo
PosMinVal=i; % e se ne memorizza la posizione i
end
end
[MinVal MaxVal]

ans = 1×2
14.6562 17.8750

[PosMinVal PosMaxVal]

ans = 1×2
4849 4769

[Ibm.Date(PosMinVal) Ibm.Date(PosMaxVal)]

ans = 1×2 datetime array


1981-04-30 1981-01-06

Si osservi che si poteva anche utilizzare la function "MaxMinPos()" precedentemente salvata in un m-file:

[MinVal,MaxVal,PosMinVal,PosMaxVal]=MinMaxPos(Ibm.Close,rowd1,rowd2);
[MinVal MaxVal]

ans = 1×2
14.6562 17.8750

[PosMinVal PosMaxVal]

ans = 1×2
4849 4769

19
[Ibm.Date(PosMinVal) Ibm.Date(PosMaxVal)]

ans = 1×2 datetime array


1981-04-30 1981-01-06

Contatori
Supponiamo adesso di voler analizzare i prezzi di chiusura del titolo Ibm andando a contare quante sono
state le giornate in cui si è avuto un rialzo del prezzo, quante sono state le giornate in cui si è avuto un
ribasso del prezzo, quante sono state le giornate in cui si è avuto un rialzo percentuale della quotazione
superiore od uguale al 10%. Sostanzialmente, dobbiamo utilizzare tre contatori ed analizzare i dati storici
nella loro completezza.

numrialzi=0; % si inizializza il contatore numrialzi


numribassi=0; % si inizializza il contatore numribassi
numrialzi10=0; % si inizializza il contatore numrialzi10
for i=2:nday % si scorre l'intero vettore dei prezzi di chiusura
if Ibm.Close(i)>Ibm.Close(i-1) % si controlla di aver avuto un rialzo
numrialzi=numrialzi+1; % in tal caso si incrementa numrialzi
elseif Ibm.Close(i)<Ibm.Close(i-1) % si controlla di aver avuto un ribasso
numribassi=numribassi+1; % in tal caso si incrementa numribassi
end
varperc=(Ibm.Close(i)-Ibm.Close(i-1))/Ibm.Close(i-1); % si calcola la var. percentuale
if varperc>=0.1 % si controlla se la varperc è superiore al 10%
numrialzi10=numrialzi10+1; % in tal caso si incrementa numrialzi10
end
end
numrialzi

numrialzi = 6905

numribassi

numribassi = 6872

numrialzi10

numrialzi10 = 12

Accumulatori
Per studiare l'andamento tendenziale (ovvero il cosiddetto "Trend") delle quotazioni di un titolo di borsa di
solito si calcola la media delle quotazioni degli ultimi 5-10-15 giorni, in modo tale da "smussare" i picchi
speculativi ed avere un andamento più "morbido". Per calcolare queste medie occorre utilizzare degli
accumulatori. Di seguito indichiamo con "p" il numero delle ultime quotazioni consecutive di cui calcolare la
media.

p=5; % a titolo di esempio, calcoliamo le medie delle ultime 5 quotazioni

medie=zeros(nday,1); % inizializziamo il vettore delle medie

20
for i=p:nday % si scorrono le quotazioni dalla p-esima
accum=0; % si inizializza l'accumulatore a zero
for h=1:p % si scorrono le p quotazioni da sommare
accum=accum+Ibm.Close(i-h+1); % si aggiorna l'accumulatore
end
medie(i)=accum/p; % si calcola la media delle p quotazioni
end

Ovviamente, evitiamo di visualizzare il vettore delle medie avendo esso 14154 componenti.

Flag
Vediamo ad esempio se il titolo Ibm ha avuto o meno una variazione percentuale dei prezzi di chiusura
superiore od uguale al 15%.

trovata=false; % si inizializza il flag al valore "false"


for i=2:nday % si scorrono le giornate
varperc=(Ibm.Close(i)-Ibm.Close(i-1))/Ibm.Close(i-1); % calcolo variazione percentuale
if varperc>=0.15 % si controlla se la var. perc. supera il 15%
trovata=true; % nel qual caso il flag prende il valore "true"
break % si può interrompere la ricerca
end
end
trovata % valore finale della variabile flag

trovata = logical
0

Liste e Maschere
Supponiamo adesso di volere la lista delle giornate in cui si è avuto un rialzo percentuale dei prezzi di
chiusura superiore od uguale al 10%.

listarialzi10=zeros(nday,1); % si inizializza la lista alla max. dimensione possibile


numelem=0; % si inizializza a 0 il numero di elementi nella lista
for i=2:nday % si scorre l'intero vettore dei prezzi di chiusura
varperc=(Ibm.Close(i)-Ibm.Close(i-1))/Ibm.Close(i-1); % si calcola la var. percentuale
if varperc>=0.10 % si controlla se la varperc è superiore al 10%
numelem=numelem+1; % si incrementa il contatore degli elementi in lista
listarialzi10(numelem)=i; % si aggiunge alla lista la componente i
end
end
listarialzi10=listarialzi10(1:numelem); % si tolgono dalla lista le componenti in eccesso
listarialzi10'

ans = 1×12
3269 6486 8131 8193 8702 9021

Ibm.Date(listarialzi10)'

21
ans = 1×12 datetime array
1975-01-28 1987-10-20 1994-04-21 1994-07-21 1996-07-25 1997-10-28 1999-04-22 2001-01-03 2001-01-

E' possibile anche determinare la corrispondente maschera, ma risulterebbe impossibile da visualizzare dato
che avrebbe 14154 componenti.

Determinazione Massimi e Minimi Valori in un Array


Supponiamo di avere una tabella, chiamata FTSEMIB, contenente i prezzi di chiusura dei titoli del FTSEMIB.
Supponiamo inoltre che tale tabella sia stata salvata nel file "DatiFTSEMIB.mat" presente nella "Current
Folder".

Carichiamo preliminarmente i dati.

load('DatiFTSEMIB.mat'); % si carica il file 'DatiFTSEMIB.mat'


FTSEMIB([1:3,end-2:end],:) % si visualizza per verifica

ans = 6×30 table

Date ATL AZM BMED BPE BZU

1 2016-01-04 23.9100 22.0700 6.9550 6.7800 16.3000

2 2016-01-05 24.2000 21.8200 6.8600 6.8650 16.5800

3 2016-01-06 23.7500 21.3700 6.4250 6.5600 16.3000

4 2018-04-26 27.4300 17.3350 6.5750 4.7680 20.7400

5 2018-04-27 27.6300 17.3050 6.6250 4.7450 20.8000

6 2018-04-30 27.5000 17.4300 6.6600 4.7920 20.9600

Per comodità, separiamo le date dalle quotazioni e memorizziamo il tutto in due array.

D=FTSEMIB.Date; % D è l'array delle date


Q=FTSEMIB{:,2:end}; % Q è l'array delle quotazioni
[nday,ntit]=size(Q); % memorizziamo la dimensione di Q

Determiniamo adesso il titolo che ha avuto la massima variazione percentuale e la data in cui ha avuto tale
variazione.

MaxVarPerc=-inf; % dovendo cercare un massimo si può inizializzare MaxVarPerc a -inf


for i=2:nday % si scorrono le giornate
for j=1:ntit % si scorrono i titoli
varperc=(Q(i,j)-Q(i-1,j))/Q(i-1,j); % si calcola la variazione percentuale
if varperc>MaxVarPerc % si controlla se si migliora il valore max
MaxVarPerc=varperc; % nel caso si aggiorna il valore max
TitMaxVarPerc=j; % si memorizza il titolo (colonna)
DayMaxVarPerc=i; % si memorizza la giornata (riga)
end
end

22
end
MaxVarPerc

MaxVarPerc = 0.3186

TitMaxVarPerc

TitMaxVarPerc = 15

DayMaxVarPerc

DayMaxVarPerc = 244

FTSEMIB.Properties.VariableNames{TitMaxVarPerc+1} % prima col. di FTSEMIB ha le date

ans =
'MS'

FTSEMIB.Date(DayMaxVarPerc)

ans = datetime
2016-12-13

Sempre a titolo di esempio, determiniamo il titolo che ha avuto il massimo ribasso percentuale e la data in cui
ha avuto tale ribasso. Si ricordi che in questo caso occorre tener conto del segno negativo della variazione
percentuale e che si devono considerare solo i ribassi.

MaxRibPerc=-inf; % dovendo cercare un massimo si può inizializzare MaxRibPerc a -inf


for i=2:nday % si scorrono le giornate (dalla 2 poiché serve la i-1)
for j=1:ntit % si scorrono i titoli
if Q(i,j)<Q(i-1,j) % si controlla di avere un ribasso
ribperc=-(Q(i,j)-Q(i-1,j))/Q(i-1,j); % si calcola il rib. perc. (-varperc)
if ribperc>MaxRibPerc % si controlla se si migliora il valore max
MaxRibPerc=ribperc; % nel caso si aggiorna il valore max
TitMaxRibPerc=j; % si memorizza il titolo (colonna)
DayMaxRibPerc=i; % si memorizza la giornata (riga)
end
end
end
end
MaxRibPerc

MaxRibPerc = 0.2529

TitMaxRibPerc

TitMaxRibPerc = 21

DayMaxRibPerc

DayMaxRibPerc = 26

23
FTSEMIB.Properties.VariableNames{TitMaxRibPerc+1} % prima col. di FTSEMIB ha le date

ans =
'SPM'

FTSEMIB.Date(DayMaxRibPerc)

ans = datetime
2016-02-08

Calcoliamo adesso per ogni titolo la massima e la minima variazione percentuale e le date in cui si sono
avute tali variazioni.

MaxVarPerc=-inf(1,ntit); % dobbiamo cercare ntit massimi, si inizializzano a -inf


DayMaxVarPerc=zeros(1,ntit); % si inizializza il vettore delle date
MinVarPerc=+inf(1,ntit); % dobbiamo cercare ntit minimi, si inizializzano a +inf
DayMinVarPerc=zeros(1,ntit); % si inizializza il vettore delle date
for j=1:ntit % per ciascun titolo dobbiamo calcolare qualcosa
for i=2:nday % si scorrono le giornate (dalla 2 poiché serve la i-1)
varperc=(Q(i,j)-Q(i-1,j))/Q(i-1,j); % si calcola la variazione percentuale
if varperc>MaxVarPerc(j) % si controlla se si migliora il valore max j-esimo
MaxVarPerc(j)=varperc; % nel caso si aggiorna il valore max j-esimo
DayMaxVarPerc(j)=i; % si memorizza la giornata (riga)
end
if varperc<MinVarPerc(j) % si controlla se si migliora il valore min j-esimo
MinVarPerc(j)=varperc; % nel caso si aggiorna il valore min j-esimo
DayMinVarPerc(j)=i; % si memorizza la giornata (riga)
end
end
end
MaxVarPerc

MaxVarPerc = 1×29
0.0505 0.1276 0.0913 0.1619 0.0799 0.0812 0.0503 0.0668

DayMaxVarPerc

DayMaxVarPerc = 1×29
558 520 28 133 220 30 51 30 133 337 273 28 239

FTSEMIB.Date(DayMaxVarPerc)'

ans = 1×29 datetime array


2018-03-08 2018-01-15 2016-02-10 2016-07-08 2016-11-09 2016-02-12 2016-03-14 2016-02-12 2016-07-

MinVarPerc

MinVarPerc = 1×29
-0.0909 -0.1375 -0.1505 -0.2461 -0.0814 -0.0914 -0.0551 -0.0919

DayMinVarPerc

24
DayMinVarPerc = 1×29
123 123 123 123 123 29 29 123 123 265 123 123 123

FTSEMIB.Date(DayMinVarPerc)'

ans = 1×29 datetime array


2016-06-24 2016-06-24 2016-06-24 2016-06-24 2016-06-24 2016-02-11 2016-02-11 2016-06-24 2016-06-

Calcoliamo infine per ogni giornata la massima e la minima variazione percentuale ed i titoli che hanno avuto
tali variazioni.

MaxVarPerc=-inf(nday,1); % dobbiamo cercare nday massimi, si inizializzano a -inf


TitMaxVarPerc=zeros(nday,1); % si inizializza il vettore dei titoli
MinVarPerc=+inf(nday,1); % dobbiamo cercare nday minimi, si inizializzano a +inf
TitMinVarPerc=zeros(nday,1); % si inizializza il vettore dei titoli
for i=2:nday % per ciascuna data dobbiamo calcolare qualcosa
for j=1:ntit % si scorrono i titoli
varperc=(Q(i,j)-Q(i-1,j))/Q(i-1,j); % si calcola la variazione percentuale
if varperc>MaxVarPerc(i) % si controlla se si migliora il valore max i-esimo
MaxVarPerc(i)=varperc; % nel caso si aggiorna il valore max i-esimo
TitMaxVarPerc(i)=j; % si memorizza il titolo (colonna)
end
if varperc<MinVarPerc(i) % si controlla se si migliora il valore min i-esimo
MinVarPerc(i)=varperc; % nel caso si aggiorna il valore min i-esimo
TitMinVarPerc(i)=j; % si memorizza il titolo (colonna)
end
end
end
MaxVarPerc'

ans = 1×593
-Inf 0.0337 0.0002 0.0253 0.0239 0.0320 0.0701 0.0305

TitMaxVarPerc'

ans = 1×593
0 17 18 20 9 20 14 4 4 19 14 18 23

MinVarPerc'

ans = 1×593
Inf -0.0145 -0.0634 -0.0417 -0.0605 -0.0438 -0.0255 -0.0275

TitMinVarPerc'

ans = 1×593
0 20 3 5 18 15 5 14 10 29 4 28 21

Ovviamente la prima componente dei vettori MaxVarPerc, TitMaxVarPerc, MinVarPerc, TitMinVarPerc, non
ha alcuna utilità poiché il ciclo "for" che scorre le giornate deve partire da i=2 (nel calcolo della variazione
percentuale serve la giornata i-1).

25

Potrebbero piacerti anche