# Value-at-Risk for Stocks: Delta-Normal Approach, EWMA

### Lecture Notes by Jakov Ivan S. Dumbrique (jdumbrique@ateneo.edu)

MATH 100.2: Topics in Financial Mathematics II \
First Semester, S.Y. 2021-2022 \
Ateneo de Manila University


```python
import numpy as np # Numerical Computing
import pandas as pd # Data wrangling
import matplotlib.pyplot as plt # Plotting
from scipy.stats import norm # statistical analysis
from statistics import NormalDist # statistical analysis

%matplotlib inline
```


```python
def get_return(df):
    return np.log(df["close"]/df["previous"])
```


```python
def one_day_alpha_percent_VaR_single_stock_delta_normal(df, N, alpha):
    
    """Returns the one-day 100(alpha)% VaR of a single stock using Delta Normal Approach.
    
    Parameters
    ----------
    df : pandas.DataFrame
        has two columns: (1) dt [str] and (2) closing price [float]
        assumes the dates are arranged from newest to oldest, and the date today is the date on the first row  
    N : int
        number of shares for the sole stock
    alpha : int
        the value to be used in calculting the 100(alpha)% VaR (e.g. 0.99, 0.95)
    
    Returns
    -------
    float (2 decimal places)
        one-day 100(alpha)% VaR of a single stock using Delta Normal Approach
    """

    S_0 = df.loc[0, "close"]
    
    # creates a new column that shifts the prices d values up (or -d values down)
    df["previous"] = df["close"].shift(-1)
    # get the daily returns
    df["return"] = df.apply(get_return, axis=1)
    
    # standard deviation of your stock returns
    sigma = df["return"].std()
    
    quantile = NormalDist().inv_cdf(alpha)
    var = N * S_0 * sigma * quantile
    
    return round(var, 2)
    
```

# EWMA for a single-asset portfolio
The one-day 99\% VaR on the portfolio is given by
		\begin{equation}
		\text{VaR}_{0.99} = |V| = NS_0\sigma_n\Phi^{-1}(0.99).
		\end{equation}
 The variance estimate $\sigma_n^2$ from the EWMA can be used as the variance of the random variable $R$, and so we assume that $R\sim N(0,\sigma_n^2)$.
 \begin{equation}
		\sigma_n^2 \approx \sum_{i=1}^{n-1}(1-\lambda)\lambda^{i-1}R_{n-i}^2,
\end{equation}
	giving us $\alpha_i = (1-\lambda)\lambda^{i-1}$, $i=1,2,\dots,n-1$.
    
$\alpha_i = \alpha_{j}= (1-\lambda)\lambda^{j}$, $j=0,1,2,\dots,n-2$

## Question:
Today is February 23, 2018. You are a portfolio risk manager who is assigned to analyze the market risk of a portfolio of 700 PLDT (TEL) shares. Assume that the one-day volatility of the stock follows an exponentially-weighted moving average model with parameter  $\lambda$=0.65
 . Determine the portfolio's one-day 99% VaR.
 



```python
def get_weights_df(df, d, ewma_par):
    """ 
    appends weights series to df
    """
    count_returns = len(df["close"])-d # gives the number of non-NaN (or non-empty) returns
    weight_lst = [(1-ewma_par)*(ewma_par**j) for j in range(count_returns)]
    df["weight"] = pd.Series(weight_lst)
    return df
```


```python
def d_day_alpha_percent_VaR_single_stock_delta_normal(df, d, N, alpha, ewma_par=None):
    
    """Returns the d-day 100(alpha)% VaR of a single stock using Delta Normal Approach.
    
    Parameters
    ----------
    df : pandas.DataFrame
        has two columns: (1) dt [str] and (2) closing price [float]
        assumes the dates are arranged from newest to oldest, and the date today is the date on the first row  
    d : int
        value of d for the d-day VaR
    N : int
        number of shares for the sole stock
    alpha : int
        the value to be used in calculting the 100(alpha)% VaR (e.g. 0.99, 0.95)
    ewma_par :float
        the value of the lambda parameter in an EWMA model for the volatility of the stock
        assumes the value is in the range (0,1)
    
    Returns
    -------
    float (2 decimal places)
        d-day 100(alpha)% VaR of a single stock using Delta Normal Approach
    """
    
    # gets the most recent stock price
    S_0 = df.loc[0, "close"]
    
    # creates a new column that shifts the prices d values up (or -d values down)
    df["previous"] = df["close"].shift(-d)
    # get the d-day returns
    df["return"] = df.apply(get_return, axis=1)
    
    #Case 1: if I will use EWMA
    if (ewma_par != None) and (0 < ewma_par < 1):
        df = get_weights_df(df, d, ewma_par)
        variance = np.nansum(df["weight"] * (df["return"]**2))
        sigma = np.sqrt(variance)
    #Case 2: I'll use the normal VaR
    else:
        # standard deviation of your stock returns
        sigma = df["return"].std()
    
    quantile = NormalDist().inv_cdf(alpha)
    var = N * S_0 * sigma * quantile
    
    return round(var, 2)
```


```python
# read the data
TEL_df = pd.read_csv("https://raw.githubusercontent.com/ateneomathdept/math100.2_2021Sem1/main/data/lectures/TEL_2018.csv") 
TEL_df
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>dt</th>
      <th>close</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>2/23/18</td>
      <td>1488.74</td>
    </tr>
    <tr>
      <th>1</th>
      <td>2/22/18</td>
      <td>1510.86</td>
    </tr>
    <tr>
      <th>2</th>
      <td>2/21/18</td>
      <td>1513.72</td>
    </tr>
    <tr>
      <th>3</th>
      <td>2/20/18</td>
      <td>1536.65</td>
    </tr>
    <tr>
      <th>4</th>
      <td>2/16/18</td>
      <td>1476.37</td>
    </tr>
    <tr>
      <th>...</th>
      <td>...</td>
      <td>...</td>
    </tr>
    <tr>
      <th>243</th>
      <td>3/2/17</td>
      <td>1430.29</td>
    </tr>
    <tr>
      <th>244</th>
      <td>3/1/17</td>
      <td>1408.94</td>
    </tr>
    <tr>
      <th>245</th>
      <td>2/28/17</td>
      <td>1394.35</td>
    </tr>
    <tr>
      <th>246</th>
      <td>2/27/17</td>
      <td>1374.93</td>
    </tr>
    <tr>
      <th>247</th>
      <td>2/24/17</td>
      <td>1367.68</td>
    </tr>
  </tbody>
</table>
<p>248 rows × 2 columns</p>
</div>




```python
get_weights_df(TEL_df, d=1, ewma_par=0.65)
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>dt</th>
      <th>close</th>
      <th>weight</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>2/23/18</td>
      <td>1488.74</td>
      <td>3.500000e-01</td>
    </tr>
    <tr>
      <th>1</th>
      <td>2/22/18</td>
      <td>1510.86</td>
      <td>2.275000e-01</td>
    </tr>
    <tr>
      <th>2</th>
      <td>2/21/18</td>
      <td>1513.72</td>
      <td>1.478750e-01</td>
    </tr>
    <tr>
      <th>3</th>
      <td>2/20/18</td>
      <td>1536.65</td>
      <td>9.611875e-02</td>
    </tr>
    <tr>
      <th>4</th>
      <td>2/16/18</td>
      <td>1476.37</td>
      <td>6.247719e-02</td>
    </tr>
    <tr>
      <th>...</th>
      <td>...</td>
      <td>...</td>
      <td>...</td>
    </tr>
    <tr>
      <th>243</th>
      <td>3/2/17</td>
      <td>1430.29</td>
      <td>1.207852e-46</td>
    </tr>
    <tr>
      <th>244</th>
      <td>3/1/17</td>
      <td>1408.94</td>
      <td>7.851038e-47</td>
    </tr>
    <tr>
      <th>245</th>
      <td>2/28/17</td>
      <td>1394.35</td>
      <td>5.103175e-47</td>
    </tr>
    <tr>
      <th>246</th>
      <td>2/27/17</td>
      <td>1374.93</td>
      <td>3.317063e-47</td>
    </tr>
    <tr>
      <th>247</th>
      <td>2/24/17</td>
      <td>1367.68</td>
      <td>NaN</td>
    </tr>
  </tbody>
</table>
<p>248 rows × 3 columns</p>
</div>




```python
d_day_alpha_percent_VaR_single_stock_delta_normal(df=TEL_df, d=1, N=700, alpha=0.99, ewma_par=0.65)
```




    41212.93




```python
d_day_alpha_percent_VaR_single_stock_delta_normal(df=TEL_df, d=1, N=700, alpha=0.99)
```




    47587.79




```python
d_day_alpha_percent_VaR_single_stock_delta_normal(df=TEL_df, d=10, N=700, alpha=0.99, ewma_par=0.65)
```




    73320.42




```python

```

23c76f830814a1c5e02096dd482794b87df61bd3
ipynb
Jupyter Notebook
lectures/1Stocks/20210921_VaRforStocks_EWMA.ipynb
ateneomathdept/math100.2_2021Sem1
ac51a30e25d57a50ef8aa25fcfc0db64da0641b9
MIT
2021-12-12T04:44:09.000Z
2021-12-12T04:44:09.000Z
lectures/1Stocks/20210921_VaRforStocks_EWMA.ipynb
ateneomathdept/math100.2_2021Sem1
ac51a30e25d57a50ef8aa25fcfc0db64da0641b9
MIT
lectures/1Stocks/20210921_VaRforStocks_EWMA.ipynb
ateneomathdept/math100.2_2021Sem1
ac51a30e25d57a50ef8aa25fcfc0db64da0641b9
MIT
2021-10-04T04:16:18.000Z
2021-10-04T04:16:18.000Z
Qwen/Qwen-72B
1. YES
2. YES