The paper you’re looking for is:
Rockafellar, R. Tyrrell, and Stanislav Uryasev. “Optimization of conditional value-at-risk.” Journal of risk 2 (2000): 21-42.
If you change rp from a number to the quantile 0.2, this is equivalent to CVaR.
julia> using JuMP, Ipopt, Statistics
julia> function min_cvar_fn(x, alpha)
model = Model(Ipopt.Optimizer)
set_silent(model)
@variable(model, z[1:length(x)] >= 0)
@variable(model, var)
@constraint(model, z .>= x .- var)
@objective(model, Min, var + 1 / alpha * sum(z) / length(z))
optimize!(model)
@assert is_solved_and_feasible(model)
return objective_value(model)
end
min_cvar_fn (generic function with 1 method)
julia> x = rand(10)
10-element Vector{Float64}:
0.2735943053314943
0.9101308567374451
0.0874812908694732
0.8289752673157755
0.42123006421472475
0.3416336067914879
0.23804878901581594
0.9742698820738032
0.9221506558571922
0.47265903686773114
julia> mean(sort(x; rev = true)[1:2])
0.9482102689654976
julia> min_cvar_fn(x, 0.2)
0.9482102415031161
You probably want something like:
model = Model(Ipopt.Optimizer)
set_silent(model)
@variable(model, minimum_shares[i] <= x[i in 1:num_contracts] <= maximum_shares[i])
set_start_value.(x, shares)
@variable(model, portfolio_losses[1:num_scenarios])
@constraint(model, portfolio_losses .== losses_matrix' * x)
@variable(model, var)
@variable(model, tvar_lower_bound <= cvar <= tvar_upper_bound)
@variable(model, z[i in 1:num_scenarios] >= 0)
@constraint(model, z .>= portfolio_losses .- var)
@constraint(model, cvar == var + 1 / alpha * sum(z) / num_scenarios)
@objective(model, Max, objective_prem_vs_initial(x))
optimize!(model)
is_success = is_solved_and_feasible(model)