Calcoli scientifici con Julia/Massimizzazione del rendimento in finanza
In finanza quando si vuole massimizzare il rendimento atteso di un portafoglio avendo n asset che lo costituiscono , formato per esempio da n azioni, si risolve la questione, minimizzando la seguente funzione obiettivo che è tipicamente un problema di programmazione lineare:
dove sono i pesi del portafoglio il vettore dei rendimenti attesi
Implementazione in Julia
[modifica | modifica sorgente]Innanzitutto installo le librerie di Julia che mi servono:
using Pkg
Pkg.add(["JuMP", "HiGHS"])
Supponiamo di considerare tre titoli : Apple (AAPL), Microsoft (MSFT), Amazon ("AMZN") . Tramite il package YFinance scarico i prezzi giornalieri degli ultimi 5 anni e trasformo i dati in un DataFrame:
using YFinance, DataFrames, Statistics
tickers = ["AAPL", "MSFT", "AMZN"]
data =get_prices.(tickers, range="5y", interval="1d")
data = data |> DataFrame
Creo un dizionario e poi un DataFrame con i prezzi di chiusura delle azioni e la rispettiva data:
prices = Dict()
for t in tickers
prices[t] = data[data.ticker.==t,"close"] # colonna dei prezzi aggiustati
end
# Converti in DataFrame unico
df = DataFrame(Date = data[data.ticker.=="AMZN","timestamp"])
for t in tickers
df[!, t] = prices[t]
end
df
Si calcolano i rendimenti attesi annui delle 3 azioni e si nota che Apple rende di più col 15,82%:
Date = reduce(vcat, df.Date)
AAPL = reduce(vcat, df.AAPL)
MSFT = reduce(vcat, df.MSFT)
AMZN = reduce(vcat, df.AMZN)
# Calcola rendimenti giornalieri
rets = dropmissing(DataFrame(
Date = Date[2:end],
AAPL = diff(log.(AAPL)),
MSFT = diff(log.(MSFT)),
AMZN = diff(log.(AMZN)),
))
# Media giornaliera → annualizzata (252 giorni)
μ = Dict(
"AAPL" => mean(rets.AAPL) * 252,
"MSFT" => mean(rets.MSFT) * 252,
"AMZN" => mean(rets.AMZN) * 252,
)
println("Rendimenti attesi annualizzati:")
println(μ)
Rendimenti attesi annualizzati:
Dict("MSFT" => 0.11644058687702825, "AMZN" => 0.07435392903921334, "AAPL" => 0.1582824969436331)
Tramite il modello di programmazione lineare HiGHS si scelgono i pesi ottimali e si nota che tutto il capitale va su Apple perché ha il rendimento atteso più alto, ma bisogna tenere conto della minimizzazione del rischio o della varianza - volatilità del portafoglio:
using JuMP, HiGHS, LinearAlgebra
mu_vec = [μ["AAPL"], μ["MSFT"], μ["AMZN"]]
n = length(mu_vec)
model = Model(HiGHS.Optimizer)
@variable(model, w[1:n] >= 0)
@constraint(model, sum(w) == 1)
@objective(model, Max, dot(mu_vec, w))
optimize!(model)
println("----------------------------------------------------------------------")
println("Pesi ottimali: ", value.(w))
println("Rendimento atteso: ", objective_value(model))
Running HiGHS 1.13.1 (git hash: 1d267d97c): Copyright (c) 2026 under Apache 2.0 license terms Using BLAS: blastrampoline LP has 1 row; 3 cols; 3 nonzeros Coefficient ranges: Matrix [1e+00, 1e+00] Cost [7e-02, 2e-01] Bound [0e+00, 0e+00] RHS [1e+00, 1e+00] Presolving model 1 rows, 1 cols, 1 nonzeros 0s 0 rows, 0 cols, 0 nonzeros 0s Presolve reductions: rows 0(-1); columns 0(-3); nonzeros 0(-3) - Reduced to empty Performed postsolve Solving the original LP from the solution after postsolve Model status : Optimal Objective value : 1.5828249694e-01 P-D objective error : 0.0000000000e+00 HiGHS run time : 0.00 ---------------------------------------------------------------------- Pesi ottimali: [1.0, 0.0, 0.0] Rendimento atteso: 0.1582824969436331