voly 0.0.104__tar.gz → 0.0.105__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: voly
3
- Version: 0.0.104
3
+ Version: 0.0.105
4
4
  Summary: Options & volatility research package
5
5
  Author-email: Manu de Cara <manu.de.cara@gmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "voly"
7
- version = "0.0.104"
7
+ version = "0.0.105"
8
8
  description = "Options & volatility research package"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -60,7 +60,7 @@ line_length = 100
60
60
  multi_line_output = 3
61
61
 
62
62
  [tool.mypy]
63
- python_version = "0.0.104"
63
+ python_version = "0.0.105"
64
64
  warn_return_any = true
65
65
  warn_unused_configs = true
66
66
  disallow_untyped_defs = true
@@ -155,6 +155,10 @@ class VolyClient:
155
155
  option_type: str = 'call') -> float:
156
156
  return iv(option_price, s, K, r, t, option_type)
157
157
 
158
+ @staticmethod
159
+ def pdf_to_calls(pdf_K: np.ndarray, s: float, K: np.ndarray, r: float, t: float):
160
+ return pdf_to_calls(pdf_K, s, K, r, t)
161
+
158
162
  # -------------------------------------------------------------------------
159
163
  # Model Fitting
160
164
  # -------------------------------------------------------------------------
@@ -356,3 +356,51 @@ def get_domain(domain_params: Tuple[float, float, int] = (-1.5, 1.5, 1000),
356
356
  else:
357
357
  raise ValueError(
358
358
  f"Invalid return_domain: {return_domain}. Must be one of ['log_moneyness', 'moneyness', 'returns', 'striKes', 'delta'].")
359
+
360
+
361
+ @catch_exception
362
+ def pdf_to_calls(pdf_K, s, K, r, t):
363
+ # Step 0: Normalize the PDF
364
+ dK = np.diff(K, prepend=K[0])
365
+ total_area = np.sum(pdf_K * dK)
366
+ pdf_K_normalized = pdf_K / total_area
367
+
368
+ # Step 1: Recover the second derivative
369
+ c2_recovered = pdf_K_normalized / np.exp(r * t)
370
+
371
+ # Step 2: Double integration using NumPy
372
+ # First integration (c2 -> c1)
373
+ c1_recovered = np.zeros_like(K)
374
+ for i in range(1, len(K)):
375
+ c1_recovered[i] = c1_recovered[i - 1] + 0.5 * (c2_recovered[i] + c2_recovered[i - 1]) * (K[i] - K[i - 1])
376
+
377
+ # Second integration (c1 -> c)
378
+ c_recovered_base = np.zeros_like(K)
379
+ for i in range(1, len(K)):
380
+ c_recovered_base[i] = c_recovered_base[i - 1] + 0.5 * (c1_recovered[i] + c1_recovered[i - 1]) * (
381
+ K[i] - K[i - 1])
382
+
383
+ # Determine the integration constants based on boundary conditions
384
+ # Find the lowest strike (deep ITM) and highest strike (deep OTM)
385
+ K_min = K[0]
386
+ K_max = K[-1]
387
+
388
+ # Boundary conditions:
389
+ # c(K_max) should be close to 0
390
+ # c(K_min) should be close to s - K_min*exp(-r*t)
391
+ c_min_target = max(0, s - K_min * np.exp(-r * t))
392
+ c_max_target = 0 # deep OTM call is worthless
393
+
394
+ # Solve for a and b in c_recovered = c_recovered_base + a*K + b
395
+ A = np.array([[1, K_min], [1, K_max]])
396
+ b_vec = np.array([c_min_target - c_recovered_base[0], c_max_target - c_recovered_base[-1]])
397
+ integration_constants = np.linalg.solve(A, b_vec)
398
+
399
+ # Apply the correction
400
+ ic_b, ic_a = integration_constants[0], integration_constants[1] # ic_a is slope, ic_b is intercept
401
+ c_recovered = c_recovered_base + ic_b + ic_a * K
402
+
403
+ # Ensure non-negative call prices
404
+ c_recovered = np.maximum(c_recovered, 0)
405
+
406
+ return c_recovered, ic_a, ic_b
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: voly
3
- Version: 0.0.104
3
+ Version: 0.0.105
4
4
  Summary: Options & volatility research package
5
5
  Author-email: Manu de Cara <manu.de.cara@gmail.com>
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes