Максимизируйте долгосрочные инвестиции Используя линейное программирование: основанный на проблеме

В этом примере показано, как использовать подход, основанный на проблеме, чтобы решить инвестиционную задачу с детерминированными возвратами по постоянному числу лет T. Проблема состоит в том, чтобы выделить ваши деньги по доступным инвестициям, чтобы максимизировать ваше итоговое богатство. Для основанного на решателе подхода смотрите, что Maximize Long-Term Investments Использует Линейное Программирование: основанный на решателе.

Формулировка задачи

Предположим, что у вас есть начальная сумма денег Capital_0 вкладывать капитал по периоду времени T годы в N облигации с нулевым купоном. Каждая связь платит фиксированную процентную ставку, соединяет инвестиции каждый год и платит принципал плюс начисленные проценты в конце срока погашения. Цель состоит в том, чтобы максимизировать общую сумму денег после T годы.

Можно включать ограничение, что никакие одни инвестиции не являются больше, чем определенная часть совокупного капитала во время инвестиций.

Этот пример показывает настройку задач на маленьком случае сначала, и затем формулирует общий случай.

Можно смоделировать это как задачу линейного программирования. Поэтому, чтобы оптимизировать ваше богатство, сформулируйте проблему с помощью подхода задачи оптимизации.

Вводный пример

Начните с небольшого примера:

  • Стартовая сумма, чтобы инвестировать Capital_0 1 000$.

  • Период времени T 5 лет.

  • Количество связей N 4.

  • К модели неинвестированные деньги имейте в наличии одну опцию B0 каждый год, которая имеет срок погашения 1 года и процентную ставку 0%.

  • Связь 1, обозначенный B1, может быть куплена в году 1, имеет срок погашения 4 лет и процентную ставку 2%.

  • Связь 2, обозначенный B2, может быть куплена в году 5, имеет срок погашения 1 года и процентную ставку 4%.

  • Связь 3, обозначенный B3, может быть куплена в году 2, имеет срок погашения 4 лет и процентную ставку 6%.

  • Связь 4, обозначенный B4, может быть куплена в году 2, имеет срок погашения 3 лет и процентную ставку 6%.

Путем разделения права преимущественной покупки B0 на 5 связей со сроком погашения 1 года и процентной ставкой 0%, эта проблема может быть эквивалентно смоделирована как наличие в общей сложности 9 доступных связей, таких это для k=1..9

  • Запись k из векторного PurchaseYears представляет начало года та связь k доступно для покупки.

  • Запись k из векторного Maturity представляет срок погашения mk из связи k.

  • Запись k из векторного MaturityYears представляет конец года та связь k доступно для продажи.

  • Запись k из векторного InterestRates представляет процентную ставку процента ρk из связи k.

Визуализируйте эту проблему горизонтальными планками, которые представляют доступные времена покупки и длительность для каждой связи.

% Time period in years
T = 5;
% Number of bonds
N = 4;
% Initial amount of money
Capital_0 = 1000;
% Total number of buying oportunities
nPtotal = N+T;
% Purchase times
PurchaseYears = [1;2;3;4;5;1;5;2;2];
% Bond durations
Maturity = [1;1;1;1;1;4;1;4;3];
% Bond sale times
MaturityYears = PurchaseYears + Maturity - 1;
% Interest rates in percent
InterestRates = [0;0;0;0;0;2;4;6;6];
% Return after one year of interest
rt = 1 + InterestRates/100;

plotInvestments(N,PurchaseYears,Maturity,InterestRates)

Переменные решения

Представляйте свои переменные решения векторным x, где x(k) сумма в долларах инвестиций в связь k, для k = 1,...,9. На зрелость, выплату для инвестиций x(k)

x(k)(1+ρk/100)mk.

Define βk=1+ρk/100 и задайте rk как совокупный доход связи k:

rk=(1+ρk/100)mk=βkmk.

x = optimvar('x',nPtotal,'LowerBound',0);
% Total returns
r = rt.^Maturity;

Целевая функция

Цель состоит в том, чтобы выбрать инвестиции, чтобы максимизировать сумму денег, собранную в конце года T. Из графика вы видите, что инвестиции собирают в различные промежуточные годы и повторно инвестируют. В конце года T, деньги, возвращенные в инвестиции 5, 7, и 8, могут быть собраны и представляют ваше итоговое богатство:

maxxx5r5+x7r7+x8r8

Создайте задачу оптимизации для максимизации и включайте целевую функцию.

interestprob = optimproblem('ObjectiveSense','maximize');
interestprob.Objective = x(5)*r(5) + x(7)*r(7) + x(8)*r(8);

Линейные ограничения: вложите капитал не больше, чем, вы имеете

Каждый год вы имеете определенную сумму в наличии денег, чтобы купить связи. Начиная с года 1, можно инвестировать первоначальный капитал в опции покупки x1 и x6, так:

x1+x6=Capital0

Затем в течение следующих лет, вы собираете возвраты из назревающих связей и повторно инвестируете их в новые доступные связи, чтобы получить систему уравнений:

x2+x8+x9=r1x1x3=r2x2x4=r3x3x5+x7=r4x4+r6x6+r9x9

investconstr = optimconstr(T,1);
investconstr(1) = x(1) + x(6) == Capital_0;
investconstr(2) = x(2) + x(8) + x(9) == r(1)*x(1);
investconstr(3) = x(3) == r(2)*x(2);
investconstr(4) = x(4) == r(3)*x(3);
investconstr(5) = x(5) + x(7) == r(4)*x(4) + r(6)*x(6) + r(9)*x(9);
interestprob.Constraints.investconstr = investconstr;

Связанные ограничения: никакое заимствование

Поскольку каждая сумма, которую инвестируют, должна быть положительной, каждая запись в векторе решения x mustBePositive. Включайте это ограничение путем установки нижней границы на векторе решения x. На векторе решения нет никакой явной верхней границы.

x.LowerBound = 0;

Решите задачу

Решите эту задачу без ограничений на сумму, которую можно инвестировать в связь. Алгоритм внутренней точки может использоваться, чтобы решить этот тип задачи линейного программирования.

options = optimoptions('linprog','Algorithm','interior-point');
[sol,fval,exitflag] = solve(interestprob,'options',options)
Solving problem using linprog.

Solution found during presolve.
sol = struct with fields:
    x: [9x1 double]

fval = 1.2625e+03
exitflag = 
    OptimalSolution

Визуализируйте решение

Выходной флаг указывает, что решатель нашел оптимальное решение. Значение fval, возвращенный как второй выходной аргумент, соответствует итоговому богатству. Смотрите на итоговую сумму инвестиций и инвестиционное выделение в зависимости от времени.

fprintf('After %d years, the return for the initial $%g is $%g \n',...
    T,Capital_0,fval);
After 5 years, the return for the initial $1000 is $1262.48 
plotInvestments(N,PurchaseYears,Maturity,InterestRates,sol.x)

Оптимальные инвестиции с ограниченными активами

Чтобы разносторонне развить ваши инвестиции, можно принять решение ограничить сумму, которую инвестируют в любую связь к определенному проценту Pmax из совокупного капитала в том году (включая возвраты для связей, которые находятся в настоящее время в их срок погашения). Вы получаете следующую систему неравенств:

x1Pmax×Capital0x2Pmax×(β1x1+β6x6)x3Pmax×(β2x2+β62x6+β8x8+β9x9)x4Pmax×(β3x3+β63x6+β82x8+β92x9)x5Pmax×(β4x4+β64x4+β83x8+β93x9)x6Pmax×Capital0x7Pmax×(β4x4+β64x4+β83x8+β93x9)x8Pmax×(β1x1+β6x6)x9Pmax×(β1x1+β6x6)

% Maximum percentage to invest in any bond
Pmax = 0.6;

constrlimit = optimconstr(nPtotal,1);
constrlimit(1) = x(1) <= Pmax*Capital_0;
constrlimit(2) = x(2) <= Pmax*(rt(1)*x(1) + rt(6)*x(6));
constrlimit(3) = x(3) <= Pmax*(rt(2)*x(2) + rt(6)^2*x(6) + rt(8)*x(8) + rt(9)*x(9));
constrlimit(4) = x(4) <= Pmax*(rt(3)*x(3) + rt(6)^3*x(6) + rt(8)^2*x(8) + rt(9)^2*x(9));
constrlimit(5) = x(5) <= Pmax*(rt(4)*x(4) + rt(6)^4*x(6) + rt(8)^3*x(8) + rt(9)^3*x(9));
constrlimit(6) = x(6) <= Pmax*Capital_0;
constrlimit(7) = x(7) <= Pmax*(rt(4)*x(4) + rt(6)^4*x(6) + rt(8)^3*x(8) + rt(9)^3*x(9));
constrlimit(8) = x(8) <= Pmax*(rt(1)*x(1) + rt(6)*x(6));
constrlimit(9) = x(9) <= Pmax*(rt(1)*x(1) + rt(6)*x(6));

interestprob.Constraints.constrlimit = constrlimit;

Решите задачу путем инвестирования не больше, чем 60% в любой актив. Постройте получившиеся покупки. Заметьте, что ваше итоговое богатство меньше инвестиций без этого ограничения.

[sol,fval] = solve(interestprob,'options',options);
Solving problem using linprog.

Minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in
feasible directions, to within the selected value of the function tolerance,
and constraints are satisfied to within the selected value of the constraint
tolerance.
fprintf('After %d years, the return for the initial $%g is $%g \n',...
    T,Capital_0,fval);
After 5 years, the return for the initial $1000 is $1207.78 
plotInvestments(N,PurchaseYears,Maturity,InterestRates,sol.x)

Модель произвольного размера

Создайте модель для общей версии проблемы. Проиллюстрируйте его с помощью T = 30 лет и 400 случайным образом сгенерированных связей с процентными ставками от 1 до 6%. Эта настройка приводит к задаче линейного программирования с 430 переменными решения.

% For reproducibility
rng default 
% Initial amount of money
Capital_0 = 1000;
% Time period in years
T = 30;
% Number of bonds
N = 400;
% Total number of buying oportunities
nPtotal = N + T;
% Generate random maturity durations
Maturity = randi([1 T-1],nPtotal,1);
% Bond 1 has a maturity period of 1 year
Maturity(1:T) = 1;
% Generate random yearly interest rate for each bond
InterestRates = randi(6,nPtotal,1);
% Bond 1 has an interest rate of 0 (not invested)
InterestRates(1:T) = 0;
% Return after one year of interest
rt = 1 + InterestRates/100;
% Compute the return at the end of the maturity period for each bond:
r = rt.^Maturity;

% Generate random purchase years for each option
PurchaseYears = zeros(nPtotal,1);
% Bond 1 is available for purchase every year
PurchaseYears(1:T)=1:T;
for i=1:N
    % Generate a random year for the bond to mature before the end of
    % the T year period
    PurchaseYears(i+T) = randi([1 T-Maturity(i+T)+1]);
end

% Compute the years where each bond reaches maturity at the end of the year
MaturityYears = PurchaseYears + Maturity - 1;

Вычислите времена, когда облигации смогут быть куплены или проданы. buyindex матрица содержит потенциальные времена покупки и sellindex матрица содержит потенциальные времена продаж для каждой связи.

buyindex = false(nPtotal,T); % allocate nPtotal-by-T matrix
for ii = 1:T
    buyindex(:,ii) = PurchaseYears == ii;
end
sellindex = false(nPtotal,T);
for ii = 1:T
    sellindex(:,ii) = MaturityYears == ii;
end

Настройте переменные оптимизации, соответствующие связям.

x = optimvar('x',nPtotal,1,'LowerBound',0);

Создайте задачу оптимизации и целевую функцию.

interestprob = optimproblem('ObjectiveSense','maximize');
interestprob.Objective = sum(x(sellindex(:,T)).*r(sellindex(:,T)));

Для удобства создайте временный массив xBuy, чьи столбцы представляют облигации, которые мы можем купить в каждом периоде времени.

xBuy = repmat(x,1,T).*double(buyindex);

Точно так же создайте временный массив xSell, чьи столбцы представляют связи, которые мы можем продать в каждом периоде времени.

xSell = repmat(x,1,T).*double(sellindex);

Возврат, сгенерированный для продажи этих границ,

xReturnFromSell = xSell.*repmat(r,1,T);

Создайте ограничение, что сумма, которую вы инвестируете в каждый период времени, является суммой, которую вы продали в предыдущем периоде времени.

interestprob.Constraints.InitialInvest = sum(xBuy(:,1)) == Capital_0;
interestprob.Constraints.InvestConstraint = sum(xBuy(:,2:T),1) == sum(xReturnFromSell(:,1:T-1),1);

Решение без содержания предела

Решите задачу.

tic
[sol,fval,exitflag] = solve(interestprob,'options',options);
Solving problem using linprog.

Minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in
feasible directions, to within the selected value of the function tolerance,
and constraints are satisfied to within the selected value of the constraint
tolerance.
toc
Elapsed time is 0.115753 seconds.

Как хорошо инвестиции делали?

fprintf('After %d years, the return for the initial $%g is $%g \n',...
    T,Capital_0,fval);
After 30 years, the return for the initial $1000 is $5167.58 

Решение с ограниченными активами

Чтобы создать ограничения, которые ограничивают часть инвестиций в каждый актив, настройте матрицу, которая отслеживает активные связи каждый раз. Выражать ограничение, что каждые инвестиции должны быть меньше Pmax времена итоговое значение, настроенное матрица, которая отслеживает значение каждых инвестиций каждый раз. Для этой большей проблемы, устанавливает максимальная часть, которая может быть сохранена к 0,4.

Pmax = 0.4;

Создайте active матрица, соответствующая временам, когда связь может быть сохранена, и cactive матрица, которая содержит совокупную длительность каждой активной связи. Так значение связи j во время t x(j)*(rt^cactive).

active = double(buyindex | sellindex);
for ii = 1:T
    active(:,ii) = double((ii >= PurchaseYears) & (ii <= MaturityYears));
end
cactive = cumsum(active,2);
cactive = cactive.*active;

Создайте матрицу, запись которой (j, p) представляет значение связи j в периоде времени p:

bondValue = repmat(x, 1, T).*active.*(rt.^(cactive));

Определите итоговое значение инвестиций в каждом временном интервале, таким образом, можно наложить ограничение на ограниченные активы. mvalue деньги, которые инвестируют во все связи в конце каждого периода времени, nPtotal- T matrix.moneyavailable является суммой по связям денег, которые инвестируют в начале периода времени, означая значение портфеля каждый раз.

constrlimit = optimconstr(nPtotal,T);
constrlimit(:,1) = xBuy(:,1) <= Pmax*Capital_0;
constrlimit(:,2:T) = xBuy(:,2:T)  <= repmat(Pmax*sum(bondValue(:,1:T-1),1), nPtotal, 1).*double(buyindex(:,2:T));
interestprob.Constraints.constrlimit = constrlimit;

Решите задачу с ограниченными активами.

tic
[sol,fval,exitflag] = solve(interestprob,'options',options);
Solving problem using linprog.

Minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in
feasible directions, to within the selected value of the function tolerance,
and constraints are satisfied to within the selected value of the constraint
tolerance.
toc
Elapsed time is 1.160039 seconds.
fprintf('After %d years, the return for the initial $%g is $%g \n',...
    T,Capital_0,fval);
After 30 years, the return for the initial $1000 is $5095.26 

Чтобы ускорить решатель, попробуйте двойной симплексный алгоритм.

options = optimoptions('linprog','Algorithm','dual-simplex');
tic
[sol,fval,exitflag] = solve(interestprob,'options',options);
Solving problem using linprog.

Optimal solution found.
toc
Elapsed time is 0.304755 seconds.
fprintf('After %d years, the return for the initial $%g is $%g \n',...
    T,Capital_0,fval);
After 30 years, the return for the initial $1000 is $5095.26 

В этом случае двойной симплексный алгоритм занял меньше времени, чтобы получить то же решение.

Качественный анализ результата

Чтобы получить ощущение решения, сравните его с суммой fmax то, что вы добрались бы, если вы могли бы инвестировать все свои стартовые деньги в одной связи с 6%-й процентной ставкой (максимальная процентная ставка) за полный 30-летний период. Можно также вычислить эквивалентную процентную ставку, соответствующую итоговому богатству.

% Maximum amount
fmax = Capital_0*(1+6/100)^T;
% Ratio (in percent)
rat = fval/fmax*100;
% Equivalent interest rate (in percent)
rsol = ((fval/Capital_0)^(1/T)-1)*100;

fprintf(['The amount collected is %g%% of the maximum amount $%g '...
    'that you would obtain from investing in one bond.\n'...
    'Your final wealth corresponds to a %g%% interest rate over the %d year '...
    'period.\n'], rat, fmax, rsol, T)
The amount collected is 88.7137% of the maximum amount $5743.49 that you would obtain from investing in one bond.
Your final wealth corresponds to a 5.57771% interest rate over the 30 year period.
plotInvestments(N,PurchaseYears,Maturity,InterestRates,sol.x,false)