# Portfolio optimization

**URL:** <https://discuss.ampl.com/t/portfolio-optimization/862>\
**Category:** Support\
**Created:** [December 17, 2023, 6:35am UTC](https://discuss.ampl.com/t/portfolio-optimization/862 "2023-12-17T06:35:10Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![Firdevs\_Uykun](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/firdevs_uykun/32/528_2.png) [@Firdevs\_Uykun](https://discuss.ampl.com/u/Firdevs_Uykun)\
**Post date:** [December 22, 2023, 9:41pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/22 "2023-12-22T21:41:16Z")

</div>

![image](https://us1.discourse-cdn.com/flex019/uploads/ampl/original/1X/443273a80183cb65108c95175c842ca91bdc79d4.png)  
I want to extend columns,19 stocks,Why is this not possible?

---

<div class="post-metadata">

**Author:** ![fdabrandao](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/fdabrandao/32/63_2.png) [@fdabrandao](https://discuss.ampl.com/u/fdabrandao)\
**Post date:** [December 22, 2023, 9:46pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/23 "2023-12-22T21:46:36Z")

</div>

You need three indices for the parameter so the easiest way to so that is to stack the original 2D dataframe into a regular dataframe with two indices and one data column. This makes it easy to add the third index corresponding to time.

---

<div class="post-metadata">

**Author:** ![Firdevs\_Uykun](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/firdevs_uykun/32/528_2.png) [@Firdevs\_Uykun](https://discuss.ampl.com/u/Firdevs_Uykun)\
**Post date:** [December 22, 2023, 9:54pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/24 "2023-12-22T21:54:25Z")

</div>

I understood,Do I have to define the names of the columns? What is the meaning of ‘S’?

---

<div class="post-metadata">

**Author:** ![fdabrandao](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/fdabrandao/32/63_2.png) [@fdabrandao](https://discuss.ampl.com/u/fdabrandao)\
**Post date:** [December 22, 2023, 10:02pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/25 "2023-12-22T22:02:22Z")

</div>

`S` is the name of the parameter that will receive the data. In your case you should replace `"S"` by `"Sigma"`. With `Sigma` defined as `param Sigma{Time, A, A};`.

---

<div class="post-metadata">

**Author:** ![Firdevs\_Uykun](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/firdevs_uykun/32/528_2.png) [@Firdevs\_Uykun](https://discuss.ampl.com/u/Firdevs_Uykun)\
**Post date:** [December 22, 2023, 10:05pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/26 "2023-12-22T22:05:54Z")

</div>

Sigma is not defined anymore, Isn’t it the new sigma df? I want to add 19 stocks,calculation of Variance will do with 19 stocks. I need 19\*19 matrix and time. After calculation of df I will write AMPL .

---

<div class="post-metadata">

**Author:** ![fdabrandao](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/fdabrandao/32/63_2.png) [@fdabrandao](https://discuss.ampl.com/u/fdabrandao)\
**Post date:** [December 22, 2023, 10:10pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/27 "2023-12-22T22:10:58Z")

</div>

What is the definition of the parameter you want to load the data into?

The dataframe in the screenshot below contains covariances for pairs of stocks for each time window:

> [@fdabrandao](#):
>
> ![Screenshot 2023-12-21 at 14.25.52](https://us1.discourse-cdn.com/flex019/uploads/ampl/original/1X/5d124ef2a579e92d7a36aefd6e4dde6a07dfb14c.png)

---

<div class="post-metadata">

**Author:** ![Firdevs\_Uykun](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/firdevs_uykun/32/528_2.png) [@Firdevs\_Uykun](https://discuss.ampl.com/u/Firdevs_Uykun)\
**Post date:** [December 22, 2023, 10:14pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/28 "2023-12-22T22:14:37Z")

</div>

This problem really hard for me. But I like this topic.Thanks for helping me.

 ![image](https://us1.discourse-cdn.com/flex019/uploads/ampl/original/1X/ecfd47b3d0bde7d7df29ec5cdf3db5b6dca485b9.png)  
I want to minimize variance,in rebalancing problem I will do it with time parameter.In mean variance Markowitz he did just one period,I want to solve this problem with multiperiod rebalancing.So time and whole data changes with the rolling window.

---

<div class="post-metadata">

**Author:** ![fdabrandao](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/fdabrandao/32/63_2.png) [@fdabrandao](https://discuss.ampl.com/u/fdabrandao)\
**Post date:** [December 22, 2023, 10:26pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/29 "2023-12-22T22:26:53Z")

</div>

In that model you have `Sigma[t,i,j]` so you need to adjust the definition of Sigma to `param Sigma{Time, A, A};` since the first index is Time. With this definition you can load a dataframe with the shape shown in my previous reply.

---

<div class="post-metadata">

**Author:** ![Firdevs\_Uykun](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/firdevs_uykun/32/528_2.png) [@Firdevs\_Uykun](https://discuss.ampl.com/u/Firdevs_Uykun)\
**Post date:** [December 22, 2023, 10:28pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/30 "2023-12-22T22:28:18Z")

</div>

But I got mismatch error in the df.column?

---

<div class="post-metadata">

**Author:** ![fdabrandao](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/fdabrandao/32/63_2.png) [@fdabrandao](https://discuss.ampl.com/u/fdabrandao)\
**Post date:** [December 22, 2023, 10:42pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/31 "2023-12-22T22:42:01Z")

</div>

The dataframe in the screenshot:

> [@fdabrandao](#):
>
> ![Screenshot 2023-12-21 at 14.25.52](https://us1.discourse-cdn.com/flex019/uploads/ampl/original/1X/5d124ef2a579e92d7a36aefd6e4dde6a07dfb14c.png)

has pairs of stocks as index values and not in the columns. There are just 4 columns, three for indices and one for values. This is the shape needed for Sigma indexed of `{Time, A, A}`.

You got the error by trying to set more column names than the number of columns in the dataframe.

---

<div class="post-metadata">

**Author:** ![Firdevs\_Uykun](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/firdevs_uykun/32/528_2.png) [@Firdevs\_Uykun](https://discuss.ampl.com/u/Firdevs_Uykun)\
**Post date:** [December 22, 2023, 10:49pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/32 "2023-12-22T22:49:15Z")

</div>

But I need to write my stock names. I need to adjust for 19 stocks.Stock1 is a stock name,right?

---

<div class="post-metadata">

**Author:** ![fdabrandao](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/fdabrandao/32/63_2.png) [@fdabrandao](https://discuss.ampl.com/u/fdabrandao)\
**Post date:** [December 22, 2023, 10:59pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/33 "2023-12-22T22:59:22Z")

</div>

No, the names of the stcoks are DIS, KO, XOM, etc.; Stock1 and Stock2 are the names of the index columns. In order to load the names of your stocks you need to do that to your original covariance dataframe.

In [Google Colab](https://colab.research.google.com/github/ampl/colab.ampl.com/blob/master/authors/fdabrandao/amplpyfinance/amplpyfinance_vs_amplpy.ipynb) you can see that being done with `pd.DataFrame(ef.cov_matrix, index=ef.tickers, columns=ef.tickers)`.

---

<div class="post-metadata">

**Author:** ![Firdevs\_Uykun](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/firdevs_uykun/32/528_2.png) [@Firdevs\_Uykun](https://discuss.ampl.com/u/Firdevs_Uykun)\
**Post date:** [December 23, 2023, 6:25am UTC](https://discuss.ampl.com/t/portfolio-optimization/862/34 "2023-12-23T06:25:28Z")

</div>

I used exactly your code but my result is different

 ![image](https://us1.discourse-cdn.com/flex019/uploads/ampl/original/1X/ce8b2b33672742b3d5bd6a9694c891e94a7b14f6.png)

---

<div class="post-metadata">

**Author:** ![Firdevs\_Uykun](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/firdevs_uykun/32/528_2.png) [@Firdevs\_Uykun](https://discuss.ampl.com/u/Firdevs_Uykun)\
**Post date:** [December 23, 2023, 6:27am UTC](https://discuss.ampl.com/t/portfolio-optimization/862/35 "2023-12-23T06:27:45Z")

</div>

Then when I look just df:

 ![image](https://us1.discourse-cdn.com/flex019/uploads/ampl/original/1X/a0f1773435888225d098f9d8b653c799d802cb33.png)

---

<div class="post-metadata">

**Author:** ![fdabrandao](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/fdabrandao/32/63_2.png) [@fdabrandao](https://discuss.ampl.com/u/fdabrandao)\
**Post date:** [December 23, 2023, 12:23pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/36 "2023-12-23T12:23:10Z")

</div>

Did you have the names in the dataframe `data`? The notebook at [Google Colab](https://colab.research.google.com/drive/1cx4NMjvGHrCyJnao3ZWus2Mzqiq3O3wI?usp=sharing) calculates optimizes the average variance scross the last 26 weeks. The code is as follows:

```python
from pypfopt import expected_returns, risk_models
from datetime import datetime, timedelta
from amplpy import AMPL
import yfinance as yf
import numpy as np
import pandas as pd
import yfinance as yf

tickers = [
    "HD", "MCD", "NKE", "KO", "PG", "SYY", "WMT", # Consumer Staples
    "CVX", "XOM", # Energy
    "AXP", "JPM", # Financials
    "JNJ", "MRK", "PFE", "WBA", # Health Care
    "BA", "CAT", "MMM", # Industrials
]
end_date = datetime.now().date()
start_date = end_date - timedelta(weeks=26)
ohlc = yf.download(tickers, start=start_date, end=end_date)
prices = ohlc["Adj Close"].dropna(how="all")

n_slices = 26
# display(prices)
slices = np.array_split(prices, n_slices)

dfs = []
for i, slice_df in enumerate(slices):
    df = risk_models.risk_matrix(slice_df, method="sample_cov").stack().to_frame()
    df.reset_index(inplace=True) # Turn the index into regular data columns
    df.columns = ["Stock1", "Stock2", "S"] # Adjust column names
    df["Time"] = i # Add new column with the index of the slice
    dfs.append(df)

sigma = pd.concat(dfs) # Concatenate all dataframes
sigma.set_index(["Time", "Stock1", "Stock2"], inplace=True) # Set the index to be (Time, Stock1, Stock2)
# display(sigma)

ampl = AMPL()
ampl.eval(
    r"""
    set Time;
    set A ordered;
    param Sigma{Time, A, A};
    param lb default 0;
    param ub default 1;
    var w{A} >= lb <= ub;
    minimize average_portfolio_variance:
        (sum {t in Time} sum {i in A, j in A} w[i] * Sigma[t, i, j] * w[j]) / card(Time);
    s.t. portfolio_weights:
        sum {i in A} w[i] = 1;
    """
)
ampl.set["Time"] = range(n_slices)
ampl.set["A"] = tickers
ampl.param["Sigma"] = sigma
ampl.option["solver"] = "gurobi"
ampl.solve()
print("minimal average variance:", ampl.get_value("average_portfolio_variance"))
ampl.get_data("w").to_pandas().plot.barh()

```

It produces the following output:

 ![Screenshot 2023-12-23 at 12.21.50](https://us1.discourse-cdn.com/flex019/uploads/ampl/original/1X/c51543fcc118da442541a48bd0a297f5e95e3a81.png)

---

<div class="post-metadata">

**Author:** ![Firdevs\_Uykun](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/firdevs_uykun/32/528_2.png) [@Firdevs\_Uykun](https://discuss.ampl.com/u/Firdevs_Uykun)\
**Post date:** [December 24, 2023, 12:06pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/37 "2023-12-24T12:06:06Z")

</div>

I think your solution is correct, but I’m confused.Why you divide card(Time) in minimization formula?The weight of asset i in time period t is denoted by wit,so I think weight of asset depend on t parameter then I wrote:

 ![image](https://us1.discourse-cdn.com/flex019/uploads/ampl/original/1X/e25c954fca0474e1647bcd5439da265fa30c10f8.png)

ampl = AMPL()  
ampl.eval(  
r"“”  
set Time;  
set A ordered;  
param Sigma{Time, A, A};  
param lb default 0;  
param ub default 1;  
var w{Time,A} \>= lb \<= ub;  
minimize average\_portfolio\_variance:  
(sum {t in Time} sum {i in A, j in A} w[t,i] \* Sigma[t, i, j] \* w[t,j]) / card(Time);  
s.t. portfolio\_weights {t in Time}:  
sum {i in A} w[t,i] = 1;  
“”"  
)  
ampl.set[“Time”] = range(n\_slices)  
ampl.set[“A”] = tickers  
ampl.param[“Sigma”] = sigma  
ampl.option[“solver”] = “gurobi”  
ampl.solve()  
print(“minimal average variance:”, ampl.get\_value(“average\_portfolio\_variance”))  
ampl.get\_data(“w”).to\_pandas().plot.barh()  
then I got:

 ![image](https://us1.discourse-cdn.com/flex019/uploads/ampl/original/1X/41fdf4e108ef8b0d1cf54d135b8c57cab7b1cf39.png)

---

<div class="post-metadata">

**Author:** ![fdabrandao](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/fdabrandao/32/63_2.png) [@fdabrandao](https://discuss.ampl.com/u/fdabrandao)\
**Post date:** [December 27, 2023, 10:42am UTC](https://discuss.ampl.com/t/portfolio-optimization/862/38 "2023-12-27T10:42:26Z")

</div>

In the model I wrote, I minimized the average variance if the weights were equal during all periods. It was just to show how to load the data. Your model minimizes the average variance while allowing different weights for each time period. It just depends on what you want to model.

---

<div class="post-metadata">

**Author:** ![Firdevs\_Uykun](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/firdevs_uykun/32/528_2.png) [@Firdevs\_Uykun](https://discuss.ampl.com/u/Firdevs_Uykun)\
**Post date:** [December 27, 2023, 10:47pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/39 "2023-12-27T22:47:57Z")

</div>

tau=240  
for t in range(tau, len(data)):  
stocks = [  
‘HD’, ‘MCD’, ‘NKE’, ‘KO’, ‘PG’, ‘SYY’, ‘WMT’, # Consumer Staples  
‘CVX’, ‘XOM’, # Energy  
‘AXP’, ‘JPM’, # Financials  
‘JNJ’, ‘MRK’, ‘PFE’, ‘WBA’, # Health Care  
‘BA’, ‘CAT’, ‘MMM’, # Industrials  
‘IRX’,# Information Technology#t-bill  
]  
stocks\_in\_sample = data[stocks][t - tau : t]  
slices = np.array\_split(data[stocks], 240)  
dfs =   
for i, slice\_df in enumerate(slices):  
df = risk\_models.risk\_matrix(slice\_df, method=“sample\_cov”).stack().to\_frame()  
df.reset\_index(inplace=True) # Turn the index into regular data columns  
df.columns = [“Stock1”, “Stock2”, “S”] # Adjust column names  
df[“Time”] = i # Add new column with the index of the slice  
dfs.append(df)  
sigma = pd.concat(dfs) # Concatenate all dataframes  
sigma.set\_index([“Time”, “Stock1”, “Stock2”], inplace=True) # Set the index to be (Time, Stock1, Stock2)  
display(sigma)  
I want to define for loop for iteration rolling window above the AMPL code.First,I wrote stocks\_in\_sample.values in the enumerate() but does not work than I wrote above code,

 ![image](https://us1.discourse-cdn.com/flex019/uploads/ampl/original/1X/a9f6c0ff060875b42825cad5438bba4031f19ec1.png)

---

<div class="post-metadata">

**Author:** ![fdabrandao](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/fdabrandao/32/63_2.png) [@fdabrandao](https://discuss.ampl.com/u/fdabrandao)\
**Post date:** [December 27, 2023, 10:53pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/40 "2023-12-27T22:53:55Z")

</div>

That error typically happens if the AMPL process is killed due to lack of enough memory available on the machine. Can you run that as you check memory usage and see if it is hitting the memory limit?

---

<div class="post-metadata">

**Author:** ![Firdevs\_Uykun](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.ampl.com/firdevs_uykun/32/528_2.png) [@Firdevs\_Uykun](https://discuss.ampl.com/u/Firdevs_Uykun)\
**Post date:** [December 27, 2023, 11:03pm UTC](https://discuss.ampl.com/t/portfolio-optimization/862/41 "2023-12-27T23:03:06Z")

</div>

I have enough memory in my machine,what I need to do? Also ı do not want slicing ı want iteration like rolling window

[Previous page](https://discuss.ampl.com/t/portfolio-optimization/862.md?page=1)

[Next page](https://discuss.ampl.com/t/portfolio-optimization/862.md?page=3)
