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 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) -> 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) -> 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) -> 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) -> 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, min_dte: float = 2.0) -> pd.DataFrame:
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['details'] = df['instrument_name'].apply(lambda x: extract_details(x))
225
- df['strike'] = df['details'].apply(lambda x: x['strike'] if x else None)
226
- df['option_type'] = df['details'].apply(lambda x: x['option_type'] if x else None)
227
- df['maturity_name'] = df['details'].apply(lambda x: x['maturity_name'] if x else None)
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 expiry date at 8:00 AM UTC
230
- df['expiry_date'] = df['details'].apply(
231
- lambda x: datetime.datetime(x['year'], x['month'], x['day'], 8, 0, 0) if x else None
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['dte'] = (df['expiry_date'] - reference_time).dt.total_seconds() / (24 * 60 * 60)
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['yte'] = df['dte'] / 365.25
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
- time_to_expiry: float,
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
- - time_to_expiry: The time to expiry in years
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
- specific_expiry_data = market_data[market_data['yte'] == time_to_expiry]
39
+ maturity_data = market_data[market_data['ytm'] == ytm]
40
40
 
41
- # Calculate the total implied variance using the model for filtered data
42
- w_model = np.array([model.svi(x, *params) for x in specific_expiry_data['log_moneyness']])
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 = specific_expiry_data['mark_iv'].values
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(w_model / time_to_expiry)
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
- 'Maturity': [],
78
- 'DTE': [],
79
- 'YTE': [],
80
- 'Success': [],
81
- 'Cost': [],
82
- 'Optimality': [],
83
- 'RMSE': [],
84
- 'MAE': [],
85
- '': [],
86
- 'Max Error': [],
87
- 'Number of Points': []
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
- unique_expiries = sorted(market_data['yte'].unique())
99
+ unique_maturities = sorted(market_data['ytm'].unique())
100
100
 
101
- for yte in unique_expiries:
101
+ for ytm in unique_maturities:
102
102
  # Get maturity name for reporting
103
- expiry_data = market_data[market_data['yte'] == yte]
104
- maturity_name = expiry_data['maturity_name'].iloc[0]
105
- dte_value = expiry_data['dte'].iloc[0]
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=(yte, market_data, SVIModel),
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
- 'dte': dte_value,
126
- 'yte': yte
125
+ 'dtm': dtm,
126
+ 'ytm': ytm
127
127
  }
128
128
 
129
129
  # Calculate model predictions for statistics
130
- w_svi = np.array([SVIModel.svi(x, *params) for x in expiry_data['log_moneyness']])
131
- iv_model = np.sqrt(w_svi / yte)
132
- iv_market = expiry_data['mark_iv'].values
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['Maturity'].append(maturity_name)
143
- fit_data['DTE'].append(dte_value)
144
- fit_data['YTE'].append(yte)
145
- fit_data['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[''].append(r2)
151
- fit_data['Max Error'].append(max_error)
152
- fit_data['Number of Points'].append(num_points)
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]['dte'])
183
+ key=lambda x: params_dict[x]['dtm'])
184
184
 
185
- # Create DataFrame for raw parameters with maturity names as columns
186
- raw_param_matrix = pd.DataFrame(
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
- jw_param_matrix = pd.DataFrame(
192
+ jw_params_matrix = pd.DataFrame(
193
193
  columns=maturity_names,
194
194
  index=SVIModel.JW_PARAM_NAMES
195
195
  )
196
196
 
197
- # Store YTE and DTE values for reference
198
- yte_values = {}
199
- dte_values = {}
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
- raw_param_matrix[maturity_name] = [a, b, sigma, rho, m]
207
+ raw_params_matrix[maturity_name] = [a, b, sigma, rho, m]
208
208
 
209
209
  # Get time to expiry
210
- yte = result['yte']
211
- yte_values[maturity_name] = yte
212
- dte_values[maturity_name] = result['dte']
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, yte)
216
- jw_param_matrix[maturity_name] = [nu, psi, p, c, nu_tilde]
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
- 'yte_values': yte_values,
221
- 'dte_values': dte_values
220
+ 'ytm_values': ytm_values,
221
+ 'dtm_values': dtm_values
222
222
  }
223
223
 
224
- raw_param_matrix.attrs.update(attrs)
225
- jw_param_matrix.attrs.update(attrs)
224
+ raw_params_matrix.attrs.update(attrs)
225
+ jw_params_matrix.attrs.update(attrs)
226
226
 
227
- return raw_param_matrix, jw_param_matrix
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
- raw_param_matrix, jw_param_matrix = create_parameters_matrix(params_dict)
258
+ raw_params_matrix, jw_params_matrix = create_parameters_matrix(params_dict)
259
259
 
260
260
  return {
261
- 'raw_param_matrix': raw_param_matrix,
262
- 'jw_param_matrix': jw_param_matrix,
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
- moneyness_params: Tuple[float, float, int] = (-2, 2, 500)
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
- - moneyness_params: Tuple of (min, max, num_points) for the moneyness grid
276
+ - log_moneyness_params: Tuple of (min, max, num_points) for the moneyness grid
277
277
 
278
278
  Returns:
279
- - moneyness_array, iv_surface
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 = moneyness_params
284
+ min_m, max_m, num_points = log_moneyness_params
285
285
 
286
- # Generate moneyness grid
287
- moneyness_array = np.linspace(min_m, max_m, num=num_points)
286
+ # Generate moneyness array
287
+ log_moneyness_array = np.linspace(min_m, max_m, num=num_points)
288
288
 
289
- # Get YTE values from the parameter matrix attributes
290
- yte_values = fit_results['fit_performance']['YTE']
291
- maturity_values = fit_results['fit_performance']['Maturity']
292
- param_matrix = fit_results['raw_param_matrix']
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, yte in zip(maturity_values, yte_values):
296
- svi_params = param_matrix[maturity].values
297
- w_svi = [SVIModel.svi(x, *svi_params) for x in moneyness_array]
298
- iv_surface[maturity] = np.sqrt(np.array(w_svi) / yte)
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.0
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, phi: float, p: float, c: float, nu_tilde: float, t: float) -> Tuple[float, float, float, float, 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 * phi) / b)
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,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: voly
3
- Version: 0.0.48
3
+ Version: 0.0.51
4
4
  Summary: Options & volatility research package
5
5
  Author-email: Manu de Cara <manu.de.cara@gmail.com>
6
6
  License: MIT
@@ -1,18 +1,18 @@
1
1
  voly/__init__.py,sha256=8xyDk7rFCn_MOD5hxuv5cxxKZvBVRiSIM7TgaMPpwpw,211
2
- voly/client.py,sha256=qkNC9CAuO6XRW9NYFNVJCead04Nntly7acU4O7TDO1o,20135
2
+ voly/client.py,sha256=zOYgZA0TTJ5bHDCBWqEyeaQ0IKuee1uAIbzk0uyW_Uw,20350
3
3
  voly/exceptions.py,sha256=PBsbn1vNMvKcCJwwJ4lBO6glD85jo1h2qiEmD7ArAjs,92
4
- voly/formulas.py,sha256=XA8E19pKQtMWNUB6qB04laifsok9E0Wt7HVq4wNM6QE,8539
5
- voly/models.py,sha256=V2VI9yK-JyfKtI4nT5i42LQSwyGvexiymNiC2V1mQn4,3659
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=Dfk-ByHpdteUiLXr0p-wRLr3VAmdyjdDBKwjwdTgCjA,9939
9
- voly/core/fit.py,sha256=O4PMihVWI1NIEFU4_RkKvT73p0Jk0tB-ot5moMXAW78,9950
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.48.dist-info/LICENSE,sha256=wcHIVbE12jfcBOai_wqBKY6xvNQU5E909xL1zZNq_2Q,1065
15
- voly-0.0.48.dist-info/METADATA,sha256=wh8I_veTd38_APRaWlz82K0g257Ax2HQfNZjprlEIIw,4092
16
- voly-0.0.48.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
17
- voly-0.0.48.dist-info/top_level.txt,sha256=ZfLw2sSxF-LrKAkgGjOmeTcw6_gD-30zvtdEY5W4B7c,5
18
- voly-0.0.48.dist-info/RECORD,,
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