voly 0.0.48__py3-none-any.whl → 0.0.51__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- voly/client.py +12 -8
 - voly/core/data.py +13 -36
 - voly/core/fit.py +76 -76
 - voly/formulas.py +20 -20
 - voly/models.py +2 -2
 - {voly-0.0.48.dist-info → voly-0.0.51.dist-info}/METADATA +1 -1
 - {voly-0.0.48.dist-info → voly-0.0.51.dist-info}/RECORD +10 -10
 - {voly-0.0.48.dist-info → voly-0.0.51.dist-info}/LICENSE +0 -0
 - {voly-0.0.48.dist-info → voly-0.0.51.dist-info}/WHEEL +0 -0
 - {voly-0.0.48.dist-info → voly-0.0.51.dist-info}/top_level.txt +0 -0
 
    
        voly/client.py
    CHANGED
    
    | 
         @@ -148,7 +148,8 @@ class VolyClient: 
     | 
|
| 
       148 
148 
     | 
    
         
             
                    return delta(s, k, r, vol, t, option_type)
         
     | 
| 
       149 
149 
     | 
    
         | 
| 
       150 
150 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       151 
     | 
    
         
            -
                def gamma(s: float, k: float, r: float, vol: float, t: float 
     | 
| 
      
 151 
     | 
    
         
            +
                def gamma(s: float, k: float, r: float, vol: float, t: float,
         
     | 
| 
      
 152 
     | 
    
         
            +
                          option_type: str = 'call') -> float:
         
     | 
| 
       152 
153 
     | 
    
         
             
                    """
         
     | 
| 
       153 
154 
     | 
    
         
             
                    Calculate option gamma.
         
     | 
| 
       154 
155 
     | 
    
         | 
| 
         @@ -162,10 +163,11 @@ class VolyClient: 
     | 
|
| 
       162 
163 
     | 
    
         
             
                    Returns:
         
     | 
| 
       163 
164 
     | 
    
         
             
                    - Gamma value
         
     | 
| 
       164 
165 
     | 
    
         
             
                    """
         
     | 
| 
       165 
     | 
    
         
            -
                    return gamma(s, k, r, vol, t)
         
     | 
| 
      
 166 
     | 
    
         
            +
                    return gamma(s, k, r, vol, t, option_type)
         
     | 
| 
       166 
167 
     | 
    
         | 
| 
       167 
168 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       168 
     | 
    
         
            -
                def vega(s: float, k: float, r: float, vol: float, t: float 
     | 
| 
      
 169 
     | 
    
         
            +
                def vega(s: float, k: float, r: float, vol: float, t: float,
         
     | 
| 
      
 170 
     | 
    
         
            +
                         option_type: str = 'call') -> float:
         
     | 
| 
       169 
171 
     | 
    
         
             
                    """
         
     | 
| 
       170 
172 
     | 
    
         
             
                    Calculate option vega.
         
     | 
| 
       171 
173 
     | 
    
         | 
| 
         @@ -179,7 +181,7 @@ class VolyClient: 
     | 
|
| 
       179 
181 
     | 
    
         
             
                    Returns:
         
     | 
| 
       180 
182 
     | 
    
         
             
                    - Vega value (for 1% change in volatility)
         
     | 
| 
       181 
183 
     | 
    
         
             
                    """
         
     | 
| 
       182 
     | 
    
         
            -
                    return vega(s, k, r, vol, t)
         
     | 
| 
      
 184 
     | 
    
         
            +
                    return vega(s, k, r, vol, t, option_type)
         
     | 
| 
       183 
185 
     | 
    
         | 
| 
       184 
186 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       185 
187 
     | 
    
         
             
                def theta(s: float, k: float, r: float, vol: float, t: float,
         
     | 
| 
         @@ -220,7 +222,8 @@ class VolyClient: 
     | 
|
| 
       220 
222 
     | 
    
         
             
                    return rho(s, k, r, vol, t, option_type)
         
     | 
| 
       221 
223 
     | 
    
         | 
| 
       222 
224 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       223 
     | 
    
         
            -
                def vanna(s: float, k: float, r: float, vol: float, t: float 
     | 
| 
      
 225 
     | 
    
         
            +
                def vanna(s: float, k: float, r: float, vol: float, t: float,
         
     | 
| 
      
 226 
     | 
    
         
            +
                          option_type: str = 'call') -> float:
         
     | 
| 
       224 
227 
     | 
    
         
             
                    """
         
     | 
| 
       225 
228 
     | 
    
         
             
                    Calculate option vanna.
         
     | 
| 
       226 
229 
     | 
    
         | 
| 
         @@ -234,10 +237,11 @@ class VolyClient: 
     | 
|
| 
       234 
237 
     | 
    
         
             
                    Returns:
         
     | 
| 
       235 
238 
     | 
    
         
             
                    - Vanna value
         
     | 
| 
       236 
239 
     | 
    
         
             
                    """
         
     | 
| 
       237 
     | 
    
         
            -
                    return vanna(s, k, r, vol, t)
         
     | 
| 
      
 240 
     | 
    
         
            +
                    return vanna(s, k, r, vol, t, option_type)
         
     | 
| 
       238 
241 
     | 
    
         | 
| 
       239 
242 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       240 
     | 
    
         
            -
                def volga(s: float, k: float, r: float, vol: float, t: float 
     | 
| 
      
 243 
     | 
    
         
            +
                def volga(s: float, k: float, r: float, vol: float, t: float,
         
     | 
| 
      
 244 
     | 
    
         
            +
                          option_type: str = 'call') -> float:
         
     | 
| 
       241 
245 
     | 
    
         
             
                    """
         
     | 
| 
       242 
246 
     | 
    
         
             
                    Calculate option volga (vomma).
         
     | 
| 
       243 
247 
     | 
    
         | 
| 
         @@ -251,7 +255,7 @@ class VolyClient: 
     | 
|
| 
       251 
255 
     | 
    
         
             
                    Returns:
         
     | 
| 
       252 
256 
     | 
    
         
             
                    - Volga value
         
     | 
| 
       253 
257 
     | 
    
         
             
                    """
         
     | 
| 
       254 
     | 
    
         
            -
                    return volga(s, k, r, vol, t)
         
     | 
| 
      
 258 
     | 
    
         
            +
                    return volga(s, k, r, vol, t, option_type)
         
     | 
| 
       255 
259 
     | 
    
         | 
| 
       256 
260 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       257 
261 
     | 
    
         
             
                def charm(s: float, k: float, r: float, vol: float, t: float,
         
     | 
    
        voly/core/data.py
    CHANGED
    
    | 
         @@ -12,7 +12,7 @@ import json 
     | 
|
| 
       12 
12 
     | 
    
         
             
            import pandas as pd
         
     | 
| 
       13 
13 
     | 
    
         
             
            import requests
         
     | 
| 
       14 
14 
     | 
    
         
             
            import time
         
     | 
| 
       15 
     | 
    
         
            -
            import datetime
         
     | 
| 
      
 15 
     | 
    
         
            +
            from datetime import datetime, timezone
         
     | 
| 
       16 
16 
     | 
    
         
             
            import re
         
     | 
| 
       17 
17 
     | 
    
         
             
            import numpy as np
         
     | 
| 
       18 
18 
     | 
    
         
             
            from typing import List, Dict, Any, Optional, Union
         
     | 
| 
         @@ -183,62 +183,39 @@ async def get_deribit_data(currency: str = "BTC") -> pd.DataFrame: 
     | 
|
| 
       183 
183 
     | 
    
         | 
| 
       184 
184 
     | 
    
         | 
| 
       185 
185 
     | 
    
         
             
            @catch_exception
         
     | 
| 
       186 
     | 
    
         
            -
            def process_option_chain(df: pd.DataFrame, currency: str 
     | 
| 
      
 186 
     | 
    
         
            +
            def process_option_chain(df: pd.DataFrame, currency: str) -> pd.DataFrame:
         
     | 
| 
       187 
187 
     | 
    
         
             
                """
         
     | 
| 
       188 
188 
     | 
    
         
             
                Process raw option chain data into a standardized format.
         
     | 
| 
       189 
189 
     | 
    
         | 
| 
       190 
190 
     | 
    
         
             
                Parameters:
         
     | 
| 
       191 
191 
     | 
    
         
             
                df (pd.DataFrame): Raw option chain data
         
     | 
| 
       192 
192 
     | 
    
         
             
                currency (str): Currency code (e.g., 'BTC', 'ETH')
         
     | 
| 
       193 
     | 
    
         
            -
                min_dte (float): Minimum days to expiry to include
         
     | 
| 
       194 
193 
     | 
    
         | 
| 
       195 
194 
     | 
    
         
             
                Returns:
         
     | 
| 
       196 
195 
     | 
    
         
             
                pd.DataFrame: Processed option chain data
         
     | 
| 
       197 
196 
     | 
    
         
             
                """
         
     | 
| 
       198 
197 
     | 
    
         
             
                logger.info(f"Processing data for {currency}...")
         
     | 
| 
       199 
198 
     | 
    
         | 
| 
       200 
     | 
    
         
            -
                # Extract instrument details
         
     | 
| 
       201 
     | 
    
         
            -
                # Format is typically BTC-DDMMMYY-STRIKE-C/P or ETH-DDMMMYY-STRIKE-C/P
         
     | 
| 
       202 
     | 
    
         
            -
                def extract_details(instrument_name):
         
     | 
| 
       203 
     | 
    
         
            -
                    pattern = f"{currency}-([\\d]{{1,2}})([A-Z]{{3}})(\\d{{2}})-([\\d]+)-([CP])"
         
     | 
| 
       204 
     | 
    
         
            -
                    match = re.match(pattern, instrument_name)
         
     | 
| 
       205 
     | 
    
         
            -
                    if match:
         
     | 
| 
       206 
     | 
    
         
            -
                        day = int(match.group(1))
         
     | 
| 
       207 
     | 
    
         
            -
                        month_str = match.group(2)
         
     | 
| 
       208 
     | 
    
         
            -
                        year = 2000 + int(match.group(3))
         
     | 
| 
       209 
     | 
    
         
            -
                        strike = float(match.group(4))
         
     | 
| 
       210 
     | 
    
         
            -
                        option_type = match.group(5)
         
     | 
| 
       211 
     | 
    
         
            -
             
     | 
| 
       212 
     | 
    
         
            -
                        month_dict = {'JAN': 1, 'FEB': 2, 'MAR': 3, 'APR': 4, 'MAY': 5, 'JUN': 6,
         
     | 
| 
       213 
     | 
    
         
            -
                                      'JUL': 7, 'AUG': 8, 'SEP': 9, 'OCT': 10, 'NOV': 11, 'DEC': 12}
         
     | 
| 
       214 
     | 
    
         
            -
                        month = month_dict.get(month_str)
         
     | 
| 
       215 
     | 
    
         
            -
             
     | 
| 
       216 
     | 
    
         
            -
                        maturity_name = f"{day}{month_str}{str(year)[-2:]}"
         
     | 
| 
       217 
     | 
    
         
            -
             
     | 
| 
       218 
     | 
    
         
            -
                        return {'day': day, 'month': month, 'year': year,
         
     | 
| 
       219 
     | 
    
         
            -
                                'strike': strike, 'option_type': option_type,
         
     | 
| 
       220 
     | 
    
         
            -
                                'maturity_name': maturity_name}
         
     | 
| 
       221 
     | 
    
         
            -
                    return None
         
     | 
| 
       222 
     | 
    
         
            -
             
     | 
| 
       223 
199 
     | 
    
         
             
                # Apply extraction to create new columns
         
     | 
| 
       224 
     | 
    
         
            -
                df[' 
     | 
| 
       225 
     | 
    
         
            -
                df[' 
     | 
| 
       226 
     | 
    
         
            -
                df[' 
     | 
| 
       227 
     | 
    
         
            -
                df[' 
     | 
| 
      
 200 
     | 
    
         
            +
                df['currency'] = df['instrument_name'].split('-')[0]
         
     | 
| 
      
 201 
     | 
    
         
            +
                df['maturity_name'] = df['instrument_name'].split('-')[1]
         
     | 
| 
      
 202 
     | 
    
         
            +
                df['strike'] = df['instrument_name'].split('-')[2]
         
     | 
| 
      
 203 
     | 
    
         
            +
                df['option_type'] = df['instrument_name'].split('-')[3]
         
     | 
| 
       228 
204 
     | 
    
         | 
| 
       229 
     | 
    
         
            -
                # Create  
     | 
| 
       230 
     | 
    
         
            -
                df[' 
     | 
| 
       231 
     | 
    
         
            -
                    lambda x: datetime. 
     | 
| 
       232 
     | 
    
         
            -
             
     | 
| 
      
 205 
     | 
    
         
            +
                # Create maturity date at 8:00 AM UTC
         
     | 
| 
      
 206 
     | 
    
         
            +
                df['maturity_date'] = pd.to_datetime(df['maturity_name'].apply(
         
     | 
| 
      
 207 
     | 
    
         
            +
                    lambda x: int(datetime.strptime(x, "%d%b%y")
         
     | 
| 
      
 208 
     | 
    
         
            +
                                  .replace(hour=8, minute=0, second=0, tzinfo=timezone.utc)
         
     | 
| 
      
 209 
     | 
    
         
            +
                                  .timestamp() * 1000)), unit='ms')
         
     | 
| 
       233 
210 
     | 
    
         | 
| 
       234 
211 
     | 
    
         
             
                # Get reference time from timestamp
         
     | 
| 
       235 
212 
     | 
    
         
             
                reference_time = datetime.datetime.fromtimestamp(df['timestamp'].iloc[0] / 1000)
         
     | 
| 
       236 
213 
     | 
    
         | 
| 
       237 
214 
     | 
    
         
             
                # Calculate days to expiry (DTE)
         
     | 
| 
       238 
     | 
    
         
            -
                df[' 
     | 
| 
      
 215 
     | 
    
         
            +
                df['dtm'] = (df['maturity_date'] - reference_time).dt.total_seconds() / (24 * 60 * 60)
         
     | 
| 
       239 
216 
     | 
    
         | 
| 
       240 
217 
     | 
    
         
             
                # Calculate time to expiry in years
         
     | 
| 
       241 
     | 
    
         
            -
                df[' 
     | 
| 
      
 218 
     | 
    
         
            +
                df['ytm'] = df['dtm'] / 365.25
         
     | 
| 
       242 
219 
     | 
    
         | 
| 
       243 
220 
     | 
    
         
             
                # Calculate implied volatility (convert from percentage)
         
     | 
| 
       244 
221 
     | 
    
         
             
                df['mark_iv'] = df['mark_iv'] / 100
         
     | 
    
        voly/core/fit.py
    CHANGED
    
    | 
         @@ -20,7 +20,7 @@ warnings.filterwarnings("ignore") 
     | 
|
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
            @catch_exception
         
     | 
| 
       22 
22 
     | 
    
         
             
            def calculate_residuals(params: List[float],
         
     | 
| 
       23 
     | 
    
         
            -
                                     
     | 
| 
      
 23 
     | 
    
         
            +
                                    ytm: float,
         
     | 
| 
       24 
24 
     | 
    
         
             
                                    market_data: pd.DataFrame,
         
     | 
| 
       25 
25 
     | 
    
         
             
                                    model: Any = SVIModel) -> np.ndarray:
         
     | 
| 
       26 
26 
     | 
    
         
             
                """
         
     | 
| 
         @@ -28,7 +28,7 @@ def calculate_residuals(params: List[float], 
     | 
|
| 
       28 
28 
     | 
    
         | 
| 
       29 
29 
     | 
    
         
             
                Parameters:
         
     | 
| 
       30 
30 
     | 
    
         
             
                - params: Model parameters (e.g., SVI parameters [a, b, sigma, rho, m])
         
     | 
| 
       31 
     | 
    
         
            -
                -  
     | 
| 
      
 31 
     | 
    
         
            +
                - ytm: The time to maturity in years
         
     | 
| 
       32 
32 
     | 
    
         
             
                - market_data: DataFrame with market data
         
     | 
| 
       33 
33 
     | 
    
         
             
                - model: Model class to use (default: SVIModel)
         
     | 
| 
       34 
34 
     | 
    
         | 
| 
         @@ -36,16 +36,16 @@ def calculate_residuals(params: List[float], 
     | 
|
| 
       36 
36 
     | 
    
         
             
                - Array of residuals
         
     | 
| 
       37 
37 
     | 
    
         
             
                """
         
     | 
| 
       38 
38 
     | 
    
         
             
                # Filter market data for the specific time to expiry
         
     | 
| 
       39 
     | 
    
         
            -
                 
     | 
| 
      
 39 
     | 
    
         
            +
                maturity_data = market_data[market_data['ytm'] == ytm]
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
                # Calculate the total implied variance using the model for filtered data
         
     | 
| 
       42 
     | 
    
         
            -
                 
     | 
| 
      
 41 
     | 
    
         
            +
                # Calculate the total implied variance (w) using the model for filtered data
         
     | 
| 
      
 42 
     | 
    
         
            +
                w = np.array([model.svi(x, *params) for x in maturity_data['log_moneyness']])
         
     | 
| 
       43 
43 
     | 
    
         | 
| 
       44 
44 
     | 
    
         
             
                # Extract the actual market implied volatilities
         
     | 
| 
       45 
     | 
    
         
            -
                iv_actual =  
     | 
| 
      
 45 
     | 
    
         
            +
                iv_actual = maturity_data['mark_iv'].values
         
     | 
| 
       46 
46 
     | 
    
         | 
| 
       47 
47 
     | 
    
         
             
                # Calculate residuals between market implied volatilities and model predictions
         
     | 
| 
       48 
     | 
    
         
            -
                residuals = iv_actual - np.sqrt( 
     | 
| 
      
 48 
     | 
    
         
            +
                residuals = iv_actual - np.sqrt(w / ytm)
         
     | 
| 
       49 
49 
     | 
    
         | 
| 
       50 
50 
     | 
    
         
             
                return residuals
         
     | 
| 
       51 
51 
     | 
    
         | 
| 
         @@ -74,17 +74,17 @@ def fit_svi_parameters(market_data: pd.DataFrame, 
     | 
|
| 
       74 
74 
     | 
    
         | 
| 
       75 
75 
     | 
    
         
             
                # Initialize data for fit performance
         
     | 
| 
       76 
76 
     | 
    
         
             
                fit_data = {
         
     | 
| 
       77 
     | 
    
         
            -
                    ' 
     | 
| 
       78 
     | 
    
         
            -
                    ' 
     | 
| 
       79 
     | 
    
         
            -
                    ' 
     | 
| 
       80 
     | 
    
         
            -
                    ' 
     | 
| 
       81 
     | 
    
         
            -
                    ' 
     | 
| 
       82 
     | 
    
         
            -
                    ' 
     | 
| 
       83 
     | 
    
         
            -
                    ' 
     | 
| 
       84 
     | 
    
         
            -
                    ' 
     | 
| 
       85 
     | 
    
         
            -
                    ' 
     | 
| 
       86 
     | 
    
         
            -
                    ' 
     | 
| 
       87 
     | 
    
         
            -
                    ' 
     | 
| 
      
 77 
     | 
    
         
            +
                    'maturity_name': [],
         
     | 
| 
      
 78 
     | 
    
         
            +
                    'dtm': [],
         
     | 
| 
      
 79 
     | 
    
         
            +
                    'ytm': [],
         
     | 
| 
      
 80 
     | 
    
         
            +
                    'fit_success': [],
         
     | 
| 
      
 81 
     | 
    
         
            +
                    'cost': [],
         
     | 
| 
      
 82 
     | 
    
         
            +
                    'optimality': [],
         
     | 
| 
      
 83 
     | 
    
         
            +
                    'rmse': [],
         
     | 
| 
      
 84 
     | 
    
         
            +
                    'mae': [],
         
     | 
| 
      
 85 
     | 
    
         
            +
                    'r2': [],
         
     | 
| 
      
 86 
     | 
    
         
            +
                    'max_error': [],
         
     | 
| 
      
 87 
     | 
    
         
            +
                    'n_point': []
         
     | 
| 
       88 
88 
     | 
    
         
             
                }
         
     | 
| 
       89 
89 
     | 
    
         | 
| 
       90 
90 
     | 
    
         
             
                # Dictionary to store parameters
         
     | 
| 
         @@ -96,13 +96,13 @@ def fit_svi_parameters(market_data: pd.DataFrame, 
     | 
|
| 
       96 
96 
     | 
    
         
             
                RESET = '\033[0m'
         
     | 
| 
       97 
97 
     | 
    
         | 
| 
       98 
98 
     | 
    
         
             
                # Get unique expiries
         
     | 
| 
       99 
     | 
    
         
            -
                 
     | 
| 
      
 99 
     | 
    
         
            +
                unique_maturities = sorted(market_data['ytm'].unique())
         
     | 
| 
       100 
100 
     | 
    
         | 
| 
       101 
     | 
    
         
            -
                for  
     | 
| 
      
 101 
     | 
    
         
            +
                for ytm in unique_maturities:
         
     | 
| 
       102 
102 
     | 
    
         
             
                    # Get maturity name for reporting
         
     | 
| 
       103 
     | 
    
         
            -
                     
     | 
| 
       104 
     | 
    
         
            -
                    maturity_name =  
     | 
| 
       105 
     | 
    
         
            -
                     
     | 
| 
      
 103 
     | 
    
         
            +
                    maturity_data = market_data[market_data['ytm'] == ytm]
         
     | 
| 
      
 104 
     | 
    
         
            +
                    maturity_name = maturity_data['maturity_name'].iloc[0]
         
     | 
| 
      
 105 
     | 
    
         
            +
                    dtm = maturity_data['dtm'].iloc[0]
         
     | 
| 
       106 
106 
     | 
    
         | 
| 
       107 
107 
     | 
    
         
             
                    logger.info(f"Optimizing for {maturity_name}...")
         
     | 
| 
       108 
108 
     | 
    
         | 
| 
         @@ -111,7 +111,7 @@ def fit_svi_parameters(market_data: pd.DataFrame, 
     | 
|
| 
       111 
111 
     | 
    
         
             
                        result = least_squares(
         
     | 
| 
       112 
112 
     | 
    
         
             
                            calculate_residuals,
         
     | 
| 
       113 
113 
     | 
    
         
             
                            initial_params,
         
     | 
| 
       114 
     | 
    
         
            -
                            args=( 
     | 
| 
      
 114 
     | 
    
         
            +
                            args=(ytm, market_data, SVIModel),
         
     | 
| 
       115 
115 
     | 
    
         
             
                            bounds=param_bounds,
         
     | 
| 
       116 
116 
     | 
    
         
             
                            max_nfev=1000
         
     | 
| 
       117 
117 
     | 
    
         
             
                        )
         
     | 
| 
         @@ -122,14 +122,14 @@ def fit_svi_parameters(market_data: pd.DataFrame, 
     | 
|
| 
       122 
122 
     | 
    
         
             
                    params = result.x
         
     | 
| 
       123 
123 
     | 
    
         
             
                    params_dict[maturity_name] = {
         
     | 
| 
       124 
124 
     | 
    
         
             
                        'params': params,
         
     | 
| 
       125 
     | 
    
         
            -
                        ' 
     | 
| 
       126 
     | 
    
         
            -
                        ' 
     | 
| 
      
 125 
     | 
    
         
            +
                        'dtm': dtm,
         
     | 
| 
      
 126 
     | 
    
         
            +
                        'ytm': ytm
         
     | 
| 
       127 
127 
     | 
    
         
             
                    }
         
     | 
| 
       128 
128 
     | 
    
         | 
| 
       129 
129 
     | 
    
         
             
                    # Calculate model predictions for statistics
         
     | 
| 
       130 
     | 
    
         
            -
                     
     | 
| 
       131 
     | 
    
         
            -
                    iv_model = np.sqrt( 
     | 
| 
       132 
     | 
    
         
            -
                    iv_market =  
     | 
| 
      
 130 
     | 
    
         
            +
                    w = np.array([SVIModel.svi(x, *params) for x in maturity_data['log_moneyness']])
         
     | 
| 
      
 131 
     | 
    
         
            +
                    iv_model = np.sqrt(w / ytm)
         
     | 
| 
      
 132 
     | 
    
         
            +
                    iv_market = maturity_data['mark_iv'].values
         
     | 
| 
       133 
133 
     | 
    
         | 
| 
       134 
134 
     | 
    
         
             
                    # Calculate statistics
         
     | 
| 
       135 
135 
     | 
    
         
             
                    rmse = np.sqrt(mean_squared_error(iv_market, iv_model))
         
     | 
| 
         @@ -139,17 +139,17 @@ def fit_svi_parameters(market_data: pd.DataFrame, 
     | 
|
| 
       139 
139 
     | 
    
         
             
                    num_points = len(expiry_data)
         
     | 
| 
       140 
140 
     | 
    
         | 
| 
       141 
141 
     | 
    
         
             
                    # Add to fit data
         
     | 
| 
       142 
     | 
    
         
            -
                    fit_data[' 
     | 
| 
       143 
     | 
    
         
            -
                    fit_data[' 
     | 
| 
       144 
     | 
    
         
            -
                    fit_data[' 
     | 
| 
       145 
     | 
    
         
            -
                    fit_data[' 
     | 
| 
       146 
     | 
    
         
            -
                    fit_data[' 
     | 
| 
       147 
     | 
    
         
            -
                    fit_data[' 
     | 
| 
       148 
     | 
    
         
            -
                    fit_data[' 
     | 
| 
       149 
     | 
    
         
            -
                    fit_data[' 
     | 
| 
       150 
     | 
    
         
            -
                    fit_data[' 
     | 
| 
       151 
     | 
    
         
            -
                    fit_data[' 
     | 
| 
       152 
     | 
    
         
            -
                    fit_data[' 
     | 
| 
      
 142 
     | 
    
         
            +
                    fit_data['maturity'].append(maturity_name)
         
     | 
| 
      
 143 
     | 
    
         
            +
                    fit_data['dtm'].append(dtm)
         
     | 
| 
      
 144 
     | 
    
         
            +
                    fit_data['ytm'].append(ytm)
         
     | 
| 
      
 145 
     | 
    
         
            +
                    fit_data['fit_success'].append(result.success)
         
     | 
| 
      
 146 
     | 
    
         
            +
                    fit_data['cost'].append(result.cost)
         
     | 
| 
      
 147 
     | 
    
         
            +
                    fit_data['optimality'].append(result.optimality)
         
     | 
| 
      
 148 
     | 
    
         
            +
                    fit_data['rmse'].append(rmse)
         
     | 
| 
      
 149 
     | 
    
         
            +
                    fit_data['mae'].append(mae)
         
     | 
| 
      
 150 
     | 
    
         
            +
                    fit_data['r2'].append(r2)
         
     | 
| 
      
 151 
     | 
    
         
            +
                    fit_data['max_error'].append(max_error)
         
     | 
| 
      
 152 
     | 
    
         
            +
                    fit_data['n_points'].append(num_points)
         
     | 
| 
       153 
153 
     | 
    
         | 
| 
       154 
154 
     | 
    
         
             
                    if result.success:
         
     | 
| 
       155 
155 
     | 
    
         
             
                        logger.info(f'Optimization for {maturity_name}: {GREEN}SUCCESS{RESET}')
         
     | 
| 
         @@ -171,7 +171,7 @@ def create_parameters_matrix(params_dict: Dict[str, Dict]) -> Tuple[pd.DataFrame 
     | 
|
| 
       171 
171 
     | 
    
         
             
                Uses maturity names as column names.
         
     | 
| 
       172 
172 
     | 
    
         | 
| 
       173 
173 
     | 
    
         
             
                Parameters:
         
     | 
| 
       174 
     | 
    
         
            -
                - params_dict: Dictionary of parameter results by maturity name
         
     | 
| 
      
 174 
     | 
    
         
            +
                - params_dict: Dictionary of raw parameter results by maturity name
         
     | 
| 
       175 
175 
     | 
    
         | 
| 
       176 
176 
     | 
    
         
             
                Returns:
         
     | 
| 
       177 
177 
     | 
    
         
             
                - Tuple of DataFrames with optimized parameters:
         
     | 
| 
         @@ -180,23 +180,23 @@ def create_parameters_matrix(params_dict: Dict[str, Dict]) -> Tuple[pd.DataFrame 
     | 
|
| 
       180 
180 
     | 
    
         
             
                """
         
     | 
| 
       181 
181 
     | 
    
         
             
                # Get maturity names in order by DTE
         
     | 
| 
       182 
182 
     | 
    
         
             
                maturity_names = sorted(params_dict.keys(),
         
     | 
| 
       183 
     | 
    
         
            -
                                        key=lambda x: params_dict[x][' 
     | 
| 
      
 183 
     | 
    
         
            +
                                        key=lambda x: params_dict[x]['dtm'])
         
     | 
| 
       184 
184 
     | 
    
         | 
| 
       185 
     | 
    
         
            -
                # Create DataFrame for raw parameters 
     | 
| 
       186 
     | 
    
         
            -
                 
     | 
| 
      
 185 
     | 
    
         
            +
                # Create DataFrame for raw parameters
         
     | 
| 
      
 186 
     | 
    
         
            +
                raw_params_matrix = pd.DataFrame(
         
     | 
| 
       187 
187 
     | 
    
         
             
                    columns=maturity_names,
         
     | 
| 
       188 
188 
     | 
    
         
             
                    index=SVIModel.PARAM_NAMES
         
     | 
| 
       189 
189 
     | 
    
         
             
                )
         
     | 
| 
       190 
190 
     | 
    
         | 
| 
       191 
191 
     | 
    
         
             
                # Create DataFrame for JW parameters
         
     | 
| 
       192 
     | 
    
         
            -
                 
     | 
| 
      
 192 
     | 
    
         
            +
                jw_params_matrix = pd.DataFrame(
         
     | 
| 
       193 
193 
     | 
    
         
             
                    columns=maturity_names,
         
     | 
| 
       194 
194 
     | 
    
         
             
                    index=SVIModel.JW_PARAM_NAMES
         
     | 
| 
       195 
195 
     | 
    
         
             
                )
         
     | 
| 
       196 
196 
     | 
    
         | 
| 
       197 
     | 
    
         
            -
                # Store  
     | 
| 
       198 
     | 
    
         
            -
                 
     | 
| 
       199 
     | 
    
         
            -
                 
     | 
| 
      
 197 
     | 
    
         
            +
                # Store YTM and DTM values for reference
         
     | 
| 
      
 198 
     | 
    
         
            +
                ytm_values = {}
         
     | 
| 
      
 199 
     | 
    
         
            +
                dtm_values = {}
         
     | 
| 
       200 
200 
     | 
    
         | 
| 
       201 
201 
     | 
    
         
             
                # Fill the matrices with optimized parameters
         
     | 
| 
       202 
202 
     | 
    
         
             
                for maturity_name in maturity_names:
         
     | 
| 
         @@ -204,27 +204,27 @@ def create_parameters_matrix(params_dict: Dict[str, Dict]) -> Tuple[pd.DataFrame 
     | 
|
| 
       204 
204 
     | 
    
         | 
| 
       205 
205 
     | 
    
         
             
                    # Extract raw SVI parameters
         
     | 
| 
       206 
206 
     | 
    
         
             
                    a, b, sigma, rho, m = result['params']
         
     | 
| 
       207 
     | 
    
         
            -
                     
     | 
| 
      
 207 
     | 
    
         
            +
                    raw_params_matrix[maturity_name] = [a, b, sigma, rho, m]
         
     | 
| 
       208 
208 
     | 
    
         | 
| 
       209 
209 
     | 
    
         
             
                    # Get time to expiry
         
     | 
| 
       210 
     | 
    
         
            -
                     
     | 
| 
       211 
     | 
    
         
            -
                     
     | 
| 
       212 
     | 
    
         
            -
                     
     | 
| 
      
 210 
     | 
    
         
            +
                    ytm = result['ytm']
         
     | 
| 
      
 211 
     | 
    
         
            +
                    ytm_values[maturity_name] = ytm
         
     | 
| 
      
 212 
     | 
    
         
            +
                    dtm_values[maturity_name] = result['dtm']
         
     | 
| 
       213 
213 
     | 
    
         | 
| 
       214 
214 
     | 
    
         
             
                    # Calculate JW parameters
         
     | 
| 
       215 
     | 
    
         
            -
                    nu, psi, p, c, nu_tilde = SVIModel.raw_to_jw_params(a, b, sigma, rho, m,  
     | 
| 
       216 
     | 
    
         
            -
                     
     | 
| 
      
 215 
     | 
    
         
            +
                    nu, psi, p, c, nu_tilde = SVIModel.raw_to_jw_params(a, b, sigma, rho, m, ytm)
         
     | 
| 
      
 216 
     | 
    
         
            +
                    jw_params_matrix[maturity_name] = [nu, psi, p, c, nu_tilde]
         
     | 
| 
       217 
217 
     | 
    
         | 
| 
       218 
218 
     | 
    
         
             
                # Store YTE and DTE as attributes in all DataFrames for reference
         
     | 
| 
       219 
219 
     | 
    
         
             
                attrs = {
         
     | 
| 
       220 
     | 
    
         
            -
                    ' 
     | 
| 
       221 
     | 
    
         
            -
                    ' 
     | 
| 
      
 220 
     | 
    
         
            +
                    'ytm_values': ytm_values,
         
     | 
| 
      
 221 
     | 
    
         
            +
                    'dtm_values': dtm_values
         
     | 
| 
       222 
222 
     | 
    
         
             
                }
         
     | 
| 
       223 
223 
     | 
    
         | 
| 
       224 
     | 
    
         
            -
                 
     | 
| 
       225 
     | 
    
         
            -
                 
     | 
| 
      
 224 
     | 
    
         
            +
                raw_params_matrix.attrs.update(attrs)
         
     | 
| 
      
 225 
     | 
    
         
            +
                jw_params_matrix.attrs.update(attrs)
         
     | 
| 
       226 
226 
     | 
    
         | 
| 
       227 
     | 
    
         
            -
                return  
     | 
| 
      
 227 
     | 
    
         
            +
                return raw_params_matrix, jw_params_matrix
         
     | 
| 
       228 
228 
     | 
    
         | 
| 
       229 
229 
     | 
    
         | 
| 
       230 
230 
     | 
    
         
             
            @catch_exception
         
     | 
| 
         @@ -255,46 +255,46 @@ def fit_model(market_data: pd.DataFrame, 
     | 
|
| 
       255 
255 
     | 
    
         
             
                )
         
     | 
| 
       256 
256 
     | 
    
         | 
| 
       257 
257 
     | 
    
         
             
                # Step 2: Create parameter matrices
         
     | 
| 
       258 
     | 
    
         
            -
                 
     | 
| 
      
 258 
     | 
    
         
            +
                raw_params_matrix, jw_params_matrix = create_parameters_matrix(params_dict)
         
     | 
| 
       259 
259 
     | 
    
         | 
| 
       260 
260 
     | 
    
         
             
                return {
         
     | 
| 
       261 
     | 
    
         
            -
                    ' 
     | 
| 
       262 
     | 
    
         
            -
                    ' 
     | 
| 
      
 261 
     | 
    
         
            +
                    'raw_params_matrix': raw_params_matrix,
         
     | 
| 
      
 262 
     | 
    
         
            +
                    'jw_params_matrix': jw_params_matrix,
         
     | 
| 
       263 
263 
     | 
    
         
             
                    'fit_performance': fit_performance,
         
     | 
| 
       264 
264 
     | 
    
         
             
                }
         
     | 
| 
       265 
265 
     | 
    
         | 
| 
       266 
266 
     | 
    
         | 
| 
       267 
267 
     | 
    
         
             
            @catch_exception
         
     | 
| 
       268 
268 
     | 
    
         
             
            def get_iv_surface(fit_results: Dict[str, Any],
         
     | 
| 
       269 
     | 
    
         
            -
                                
     | 
| 
      
 269 
     | 
    
         
            +
                               log_moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
         
     | 
| 
       270 
270 
     | 
    
         
             
                               ) -> Dict[str, Any]:
         
     | 
| 
       271 
271 
     | 
    
         
             
                """
         
     | 
| 
       272 
272 
     | 
    
         
             
                Generate implied volatility surface using optimized SVI parameters.
         
     | 
| 
       273 
273 
     | 
    
         | 
| 
       274 
274 
     | 
    
         
             
                Parameters:
         
     | 
| 
       275 
275 
     | 
    
         
             
                - fit_results: results from fit_model()
         
     | 
| 
       276 
     | 
    
         
            -
                -  
     | 
| 
      
 276 
     | 
    
         
            +
                - log_moneyness_params: Tuple of (min, max, num_points) for the moneyness grid
         
     | 
| 
       277 
277 
     | 
    
         | 
| 
       278 
278 
     | 
    
         
             
                Returns:
         
     | 
| 
       279 
     | 
    
         
            -
                -  
     | 
| 
      
 279 
     | 
    
         
            +
                - x_domain, iv_surface
         
     | 
| 
       280 
280 
     | 
    
         
             
                """
         
     | 
| 
       281 
281 
     | 
    
         
             
                iv_surface = {}
         
     | 
| 
       282 
282 
     | 
    
         | 
| 
       283 
283 
     | 
    
         
             
                # Extract moneyness parameters
         
     | 
| 
       284 
     | 
    
         
            -
                min_m, max_m, num_points =  
     | 
| 
      
 284 
     | 
    
         
            +
                min_m, max_m, num_points = log_moneyness_params
         
     | 
| 
       285 
285 
     | 
    
         | 
| 
       286 
     | 
    
         
            -
                # Generate moneyness  
     | 
| 
       287 
     | 
    
         
            -
                 
     | 
| 
      
 286 
     | 
    
         
            +
                # Generate moneyness array
         
     | 
| 
      
 287 
     | 
    
         
            +
                log_moneyness_array = np.linspace(min_m, max_m, num=num_points)
         
     | 
| 
       288 
288 
     | 
    
         | 
| 
       289 
     | 
    
         
            -
                # Get  
     | 
| 
       290 
     | 
    
         
            -
                 
     | 
| 
       291 
     | 
    
         
            -
                maturity_values = fit_results['fit_performance'][' 
     | 
| 
       292 
     | 
    
         
            -
                 
     | 
| 
      
 289 
     | 
    
         
            +
                # Get YTM values from the parameter matrix attributes
         
     | 
| 
      
 290 
     | 
    
         
            +
                ytm_values = fit_results['fit_performance']['ytm']
         
     | 
| 
      
 291 
     | 
    
         
            +
                maturity_values = fit_results['fit_performance']['maturity_name']
         
     | 
| 
      
 292 
     | 
    
         
            +
                raw_params_matrix = fit_results['raw_params_matrix']
         
     | 
| 
       293 
293 
     | 
    
         | 
| 
       294 
294 
     | 
    
         
             
                # Generate implied volatility for each expiry
         
     | 
| 
       295 
     | 
    
         
            -
                for maturity,  
     | 
| 
       296 
     | 
    
         
            -
                    svi_params =  
     | 
| 
       297 
     | 
    
         
            -
                    w_svi = [SVIModel.svi(x, *svi_params) for x in  
     | 
| 
       298 
     | 
    
         
            -
                    iv_surface[maturity] = np.sqrt(np.array(w_svi) /  
     | 
| 
      
 295 
     | 
    
         
            +
                for maturity, ytm in zip(maturity_values, ytm_values):
         
     | 
| 
      
 296 
     | 
    
         
            +
                    svi_params = raw_params_matrix[maturity].values
         
     | 
| 
      
 297 
     | 
    
         
            +
                    w_svi = [SVIModel.svi(x, *svi_params) for x in log_moneyness_array]
         
     | 
| 
      
 298 
     | 
    
         
            +
                    iv_surface[maturity] = np.sqrt(np.array(w_svi) / ytm)
         
     | 
| 
       299 
299 
     | 
    
         | 
| 
       300 
300 
     | 
    
         
             
                return moneyness_array, iv_surface
         
     | 
    
        voly/formulas.py
    CHANGED
    
    | 
         @@ -90,21 +90,21 @@ def delta(s: float, k: float, r: float, vol: float, t: float, option_type: str = 
     | 
|
| 
       90 
90 
     | 
    
         | 
| 
       91 
91 
     | 
    
         
             
            @catch_exception
         
     | 
| 
       92 
92 
     | 
    
         
             
            @vectorize_inputs
         
     | 
| 
       93 
     | 
    
         
            -
            def gamma(s: float, k: float, r: float, vol: float, t: float) -> float:
         
     | 
| 
      
 93 
     | 
    
         
            +
            def gamma(s: float, k: float, r: float, vol: float, t: float, option_type: str = 'call') -> float:
         
     | 
| 
       94 
94 
     | 
    
         
             
                if vol <= 0 or t <= 0:
         
     | 
| 
       95 
95 
     | 
    
         
             
                    return 0.0
         
     | 
| 
       96 
96 
     | 
    
         | 
| 
       97 
     | 
    
         
            -
                d1_val = d1(s, k, r, vol, t)
         
     | 
| 
      
 97 
     | 
    
         
            +
                d1_val = d1(s, k, r, vol, t, option_type)
         
     | 
| 
       98 
98 
     | 
    
         
             
                return norm.pdf(d1_val) / (s * vol * np.sqrt(t))
         
     | 
| 
       99 
99 
     | 
    
         | 
| 
       100 
100 
     | 
    
         | 
| 
       101 
101 
     | 
    
         
             
            @catch_exception
         
     | 
| 
       102 
102 
     | 
    
         
             
            @vectorize_inputs
         
     | 
| 
       103 
     | 
    
         
            -
            def vega(s: float, k: float, r: float, vol: float, t: float) -> float:
         
     | 
| 
      
 103 
     | 
    
         
            +
            def vega(s: float, k: float, r: float, vol: float, t: float, option_type: str = 'call') -> float:
         
     | 
| 
       104 
104 
     | 
    
         
             
                if vol <= 0 or t <= 0:
         
     | 
| 
       105 
105 
     | 
    
         
             
                    return 0.0
         
     | 
| 
       106 
106 
     | 
    
         | 
| 
       107 
     | 
    
         
            -
                d1_val = d1(s, k, r, vol, t)
         
     | 
| 
      
 107 
     | 
    
         
            +
                d1_val = d1(s, k, r, vol, t, option_type)
         
     | 
| 
       108 
108 
     | 
    
         
             
                return s * norm.pdf(d1_val) * np.sqrt(t) / 100  # Divided by 100 for 1% change
         
     | 
| 
       109 
109 
     | 
    
         | 
| 
       110 
110 
     | 
    
         | 
| 
         @@ -114,8 +114,8 @@ def theta(s: float, k: float, r: float, vol: float, t: float, option_type: str = 
     | 
|
| 
       114 
114 
     | 
    
         
             
                if vol <= 0 or t <= 0:
         
     | 
| 
       115 
115 
     | 
    
         
             
                    return 0.0
         
     | 
| 
       116 
116 
     | 
    
         | 
| 
       117 
     | 
    
         
            -
                d1_val = d1(s, k, r, vol, t)
         
     | 
| 
       118 
     | 
    
         
            -
                d2_val = d2(s, k, r, vol, t)
         
     | 
| 
      
 117 
     | 
    
         
            +
                d1_val = d1(s, k, r, vol, t, option_type)
         
     | 
| 
      
 118 
     | 
    
         
            +
                d2_val = d2(s, k, r, vol, t, option_type)
         
     | 
| 
       119 
119 
     | 
    
         | 
| 
       120 
120 
     | 
    
         
             
                # First part of theta (same for both call and put)
         
     | 
| 
       121 
121 
     | 
    
         
             
                theta_part1 = -s * norm.pdf(d1_val) * vol / (2 * np.sqrt(t))
         
     | 
| 
         @@ -136,7 +136,7 @@ def rho(s: float, k: float, r: float, vol: float, t: float, option_type: str = ' 
     | 
|
| 
       136 
136 
     | 
    
         
             
                if vol <= 0 or t <= 0:
         
     | 
| 
       137 
137 
     | 
    
         
             
                    return 0.0
         
     | 
| 
       138 
138 
     | 
    
         | 
| 
       139 
     | 
    
         
            -
                d2_val = d2(s, k, r, vol, t)
         
     | 
| 
      
 139 
     | 
    
         
            +
                d2_val = d2(s, k, r, vol, t, option_type)
         
     | 
| 
       140 
140 
     | 
    
         | 
| 
       141 
141 
     | 
    
         
             
                if option_type.lower() in ["call", "c"]:
         
     | 
| 
       142 
142 
     | 
    
         
             
                    return k * t * np.exp(-r * t) * norm.cdf(d2_val) / 100
         
     | 
| 
         @@ -146,24 +146,24 @@ def rho(s: float, k: float, r: float, vol: float, t: float, option_type: str = ' 
     | 
|
| 
       146 
146 
     | 
    
         | 
| 
       147 
147 
     | 
    
         
             
            @catch_exception
         
     | 
| 
       148 
148 
     | 
    
         
             
            @vectorize_inputs
         
     | 
| 
       149 
     | 
    
         
            -
            def vanna(s: float, k: float, r: float, vol: float, t: float) -> float:
         
     | 
| 
      
 149 
     | 
    
         
            +
            def vanna(s: float, k: float, r: float, vol: float, t: float, option_type: str = 'call') -> float:
         
     | 
| 
       150 
150 
     | 
    
         
             
                if vol <= 0 or t <= 0:
         
     | 
| 
       151 
151 
     | 
    
         
             
                    return 0.0
         
     | 
| 
       152 
152 
     | 
    
         | 
| 
       153 
     | 
    
         
            -
                d1_val = d1(s, k, r, vol, t)
         
     | 
| 
       154 
     | 
    
         
            -
                d2_val = d2(s, k, r, vol, t)
         
     | 
| 
      
 153 
     | 
    
         
            +
                d1_val = d1(s, k, r, vol, t, option_type)
         
     | 
| 
      
 154 
     | 
    
         
            +
                d2_val = d2(s, k, r, vol, t, option_type)
         
     | 
| 
       155 
155 
     | 
    
         | 
| 
       156 
156 
     | 
    
         
             
                return -norm.pdf(d1_val) * d2_val / vol
         
     | 
| 
       157 
157 
     | 
    
         | 
| 
       158 
158 
     | 
    
         | 
| 
       159 
159 
     | 
    
         
             
            @catch_exception
         
     | 
| 
       160 
160 
     | 
    
         
             
            @vectorize_inputs
         
     | 
| 
       161 
     | 
    
         
            -
            def volga(s: float, k: float, r: float, vol: float, t: float) -> float:
         
     | 
| 
      
 161 
     | 
    
         
            +
            def volga(s: float, k: float, r: float, vol: float, t: float, option_type: str = 'call') -> float:
         
     | 
| 
       162 
162 
     | 
    
         
             
                if vol <= 0 or t <= 0:
         
     | 
| 
       163 
163 
     | 
    
         
             
                    return 0.0
         
     | 
| 
       164 
164 
     | 
    
         | 
| 
       165 
     | 
    
         
            -
                d1_val = d1(s, k, r, vol, t)
         
     | 
| 
       166 
     | 
    
         
            -
                d2_val = d2(s, k, r, vol, t)
         
     | 
| 
      
 165 
     | 
    
         
            +
                d1_val = d1(s, k, r, vol, t, option_type)
         
     | 
| 
      
 166 
     | 
    
         
            +
                d2_val = d2(s, k, r, vol, t, option_type)
         
     | 
| 
       167 
167 
     | 
    
         | 
| 
       168 
168 
     | 
    
         
             
                return s * norm.pdf(d1_val) * np.sqrt(t) * d1_val * d2_val / vol
         
     | 
| 
       169 
169 
     | 
    
         | 
| 
         @@ -174,8 +174,8 @@ def charm(s: float, k: float, r: float, vol: float, t: float, option_type: str = 
     | 
|
| 
       174 
174 
     | 
    
         
             
                if vol <= 0 or t <= 0:
         
     | 
| 
       175 
175 
     | 
    
         
             
                    return 0.0
         
     | 
| 
       176 
176 
     | 
    
         | 
| 
       177 
     | 
    
         
            -
                d1_val = d1(s, k, r, vol, t)
         
     | 
| 
       178 
     | 
    
         
            -
                d2_val = d2(s, k, r, vol, t)
         
     | 
| 
      
 177 
     | 
    
         
            +
                d1_val = d1(s, k, r, vol, t, option_type)
         
     | 
| 
      
 178 
     | 
    
         
            +
                d2_val = d2(s, k, r, vol, t, option_type)
         
     | 
| 
       179 
179 
     | 
    
         | 
| 
       180 
180 
     | 
    
         
             
                # First term is the same for calls and puts
         
     | 
| 
       181 
181 
     | 
    
         
             
                term1 = -norm.pdf(d1_val) * d1_val / (2 * t)
         
     | 
| 
         @@ -187,7 +187,7 @@ def charm(s: float, k: float, r: float, vol: float, t: float, option_type: str = 
     | 
|
| 
       187 
187 
     | 
    
         
             
                    term2 = r * np.exp(-r * t) * norm.cdf(-d2_val)
         
     | 
| 
       188 
188 
     | 
    
         | 
| 
       189 
189 
     | 
    
         
             
                # Return charm per day (t is in years)
         
     | 
| 
       190 
     | 
    
         
            -
                return (term1 + term2) / 365. 
     | 
| 
      
 190 
     | 
    
         
            +
                return (term1 + term2) / 365.25
         
     | 
| 
       191 
191 
     | 
    
         | 
| 
       192 
192 
     | 
    
         | 
| 
       193 
193 
     | 
    
         
             
            @catch_exception
         
     | 
| 
         @@ -197,12 +197,12 @@ def greeks(s: float, k: float, r: float, vol: float, t: float, 
     | 
|
| 
       197 
197 
     | 
    
         
             
                return {
         
     | 
| 
       198 
198 
     | 
    
         
             
                    'price': bs(s, k, r, vol, t, option_type),
         
     | 
| 
       199 
199 
     | 
    
         
             
                    'delta': delta(s, k, r, vol, t, option_type),
         
     | 
| 
       200 
     | 
    
         
            -
                    'gamma': gamma(s, k, r, vol, t),
         
     | 
| 
       201 
     | 
    
         
            -
                    'vega': vega(s, k, r, vol, t),
         
     | 
| 
      
 200 
     | 
    
         
            +
                    'gamma': gamma(s, k, r, vol, t, option_type),
         
     | 
| 
      
 201 
     | 
    
         
            +
                    'vega': vega(s, k, r, vol, t, option_type),
         
     | 
| 
       202 
202 
     | 
    
         
             
                    'theta': theta(s, k, r, vol, t, option_type),
         
     | 
| 
       203 
203 
     | 
    
         
             
                    'rho': rho(s, k, r, vol, t, option_type),
         
     | 
| 
       204 
     | 
    
         
            -
                    'vanna': vanna(s, k, r, vol, t),
         
     | 
| 
       205 
     | 
    
         
            -
                    'volga': volga(s, k, r, vol, t),
         
     | 
| 
      
 204 
     | 
    
         
            +
                    'vanna': vanna(s, k, r, vol, t, option_type),
         
     | 
| 
      
 205 
     | 
    
         
            +
                    'volga': volga(s, k, r, vol, t, option_type),
         
     | 
| 
       206 
206 
     | 
    
         
             
                    'charm': charm(s, k, r, vol, t, option_type)
         
     | 
| 
       207 
207 
     | 
    
         
             
                }
         
     | 
| 
       208 
208 
     | 
    
         | 
    
        voly/models.py
    CHANGED
    
    | 
         @@ -67,11 +67,11 @@ class SVIModel: 
     | 
|
| 
       67 
67 
     | 
    
         
             
                    return nu, psi, p, c, nu_tilde
         
     | 
| 
       68 
68 
     | 
    
         | 
| 
       69 
69 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       70 
     | 
    
         
            -
                def jw_to_raw_params(nu: float,  
     | 
| 
      
 70 
     | 
    
         
            +
                def jw_to_raw_params(nu: float, psi: float, p: float, c: float, nu_tilde: float, t: float) -> Tuple[float, float, float, float, float]:
         
     | 
| 
       71 
71 
     | 
    
         
             
                    w = nu * t
         
     | 
| 
       72 
72 
     | 
    
         
             
                    b = (c + p) / 2
         
     | 
| 
       73 
73 
     | 
    
         
             
                    rho = (c - p) / (c + p)
         
     | 
| 
       74 
     | 
    
         
            -
                    beta = rho - ((2 * w *  
     | 
| 
      
 74 
     | 
    
         
            +
                    beta = rho - ((2 * w * psi) / b)
         
     | 
| 
       75 
75 
     | 
    
         
             
                    alpha = np.sign(beta) * (np.sqrt((1 / (beta ** 2)) - 1))
         
     | 
| 
       76 
76 
     | 
    
         
             
                    m = (((nu ** 2) - (nu_tilde ** 2)) * t) / (
         
     | 
| 
       77 
77 
     | 
    
         
             
                            b * ((-rho) + (np.sign(alpha) * np.sqrt(1 + alpha ** 2)) - (alpha * np.sqrt(1 - rho ** 2))))
         
     | 
| 
         @@ -1,18 +1,18 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            voly/__init__.py,sha256=8xyDk7rFCn_MOD5hxuv5cxxKZvBVRiSIM7TgaMPpwpw,211
         
     | 
| 
       2 
     | 
    
         
            -
            voly/client.py,sha256= 
     | 
| 
      
 2 
     | 
    
         
            +
            voly/client.py,sha256=zOYgZA0TTJ5bHDCBWqEyeaQ0IKuee1uAIbzk0uyW_Uw,20350
         
     | 
| 
       3 
3 
     | 
    
         
             
            voly/exceptions.py,sha256=PBsbn1vNMvKcCJwwJ4lBO6glD85jo1h2qiEmD7ArAjs,92
         
     | 
| 
       4 
     | 
    
         
            -
            voly/formulas.py,sha256= 
     | 
| 
       5 
     | 
    
         
            -
            voly/models.py,sha256= 
     | 
| 
      
 4 
     | 
    
         
            +
            voly/formulas.py,sha256=Xgaq4lx1fNzRfu9W84fMNeH6GRJ0FNFNUUUYn5ffjjE,8843
         
     | 
| 
      
 5 
     | 
    
         
            +
            voly/models.py,sha256=LXXIlpXZQEfXTuCngxC8Hd3bWtw6wdXDCSGxTLmHM-c,3659
         
     | 
| 
       6 
6 
     | 
    
         
             
            voly/core/__init__.py,sha256=bu6fS2I1Pj9fPPnl-zY3L7NqrZSY5Zy6NY2uMUvdhKs,183
         
     | 
| 
       7 
7 
     | 
    
         
             
            voly/core/charts.py,sha256=T8cogkiHj8NcFxfARumNvAjLJUAxsMlHUOVgshwjye8,26474
         
     | 
| 
       8 
     | 
    
         
            -
            voly/core/data.py,sha256= 
     | 
| 
       9 
     | 
    
         
            -
            voly/core/fit.py,sha256= 
     | 
| 
      
 8 
     | 
    
         
            +
            voly/core/data.py,sha256=gEtmsp-cgCSdAWhnCrOHjrjUTfGJ_1NWkIEeHAkNkAg,8904
         
     | 
| 
      
 9 
     | 
    
         
            +
            voly/core/fit.py,sha256=PCKedwjY2Xsl_Gv9t46dAnEnFbz0T1oJsZsb__GWCSw,9878
         
     | 
| 
       10 
10 
     | 
    
         
             
            voly/core/interpolate.py,sha256=ztVIePJZOh-CIbn69wkh1JW2rKywNe2FEewRN0zcSAo,8185
         
     | 
| 
       11 
11 
     | 
    
         
             
            voly/core/rnd.py,sha256=8FTU-Qp9epW9yE4XSOdiFGIRXrGyXqF6mVgZn1NMvxk,11813
         
     | 
| 
       12 
12 
     | 
    
         
             
            voly/utils/__init__.py,sha256=E05mWatyC-PDOsCxQV1p5Xi1IgpOomxrNURyCx_gB-w,200
         
     | 
| 
       13 
13 
     | 
    
         
             
            voly/utils/logger.py,sha256=4-_2bVJmq17Q0d7Rd2mPg1AeR8gxv6EPvcmBDMFWcSM,1744
         
     | 
| 
       14 
     | 
    
         
            -
            voly-0.0. 
     | 
| 
       15 
     | 
    
         
            -
            voly-0.0. 
     | 
| 
       16 
     | 
    
         
            -
            voly-0.0. 
     | 
| 
       17 
     | 
    
         
            -
            voly-0.0. 
     | 
| 
       18 
     | 
    
         
            -
            voly-0.0. 
     | 
| 
      
 14 
     | 
    
         
            +
            voly-0.0.51.dist-info/LICENSE,sha256=wcHIVbE12jfcBOai_wqBKY6xvNQU5E909xL1zZNq_2Q,1065
         
     | 
| 
      
 15 
     | 
    
         
            +
            voly-0.0.51.dist-info/METADATA,sha256=FCA6dznopdWOB3Yt7cwscidzTclrUT4og6kHq3F5xUY,4092
         
     | 
| 
      
 16 
     | 
    
         
            +
            voly-0.0.51.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
         
     | 
| 
      
 17 
     | 
    
         
            +
            voly-0.0.51.dist-info/top_level.txt,sha256=ZfLw2sSxF-LrKAkgGjOmeTcw6_gD-30zvtdEY5W4B7c,5
         
     | 
| 
      
 18 
     | 
    
         
            +
            voly-0.0.51.dist-info/RECORD,,
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     |