voly 0.0.72__py3-none-any.whl → 0.0.74__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 +8 -4
- voly/core/charts.py +46 -93
- voly/core/fit.py +1 -1
- {voly-0.0.72.dist-info → voly-0.0.74.dist-info}/METADATA +1 -1
- {voly-0.0.72.dist-info → voly-0.0.74.dist-info}/RECORD +8 -8
- {voly-0.0.72.dist-info → voly-0.0.74.dist-info}/LICENSE +0 -0
- {voly-0.0.72.dist-info → voly-0.0.74.dist-info}/WHEEL +0 -0
- {voly-0.0.72.dist-info → voly-0.0.74.dist-info}/top_level.txt +0 -0
voly/client.py
CHANGED
|
@@ -361,16 +361,16 @@ class VolyClient:
|
|
|
361
361
|
- return_domain: str Domain for x-axis values ('log_moneyness', 'moneyness', 'strikes', 'delta')
|
|
362
362
|
|
|
363
363
|
Returns:
|
|
364
|
-
-
|
|
364
|
+
- Surface. Dict composed of (iv_surface, x_surface)
|
|
365
365
|
"""
|
|
366
366
|
# Generate the surface
|
|
367
|
-
|
|
367
|
+
surface = get_iv_surface(
|
|
368
368
|
fit_results=fit_results,
|
|
369
369
|
log_moneyness_params=log_moneyness_params,
|
|
370
370
|
return_domain=return_domain
|
|
371
371
|
)
|
|
372
372
|
|
|
373
|
-
return
|
|
373
|
+
return surface
|
|
374
374
|
|
|
375
375
|
@staticmethod
|
|
376
376
|
def plot_model(fit_results: pd.DataFrame,
|
|
@@ -393,7 +393,11 @@ class VolyClient:
|
|
|
393
393
|
plots = {}
|
|
394
394
|
|
|
395
395
|
# Generate IV surface and domain
|
|
396
|
-
|
|
396
|
+
surface = get_iv_surface(fit_results, log_moneyness_params, return_domain)
|
|
397
|
+
|
|
398
|
+
# Get iv_surface and x_surface from the return value
|
|
399
|
+
iv_surface = surface['iv_surface']
|
|
400
|
+
x_surface = surface['x_surface']
|
|
397
401
|
|
|
398
402
|
# Plot volatility smiles
|
|
399
403
|
plots['smiles'] = plot_all_smiles(
|
voly/core/charts.py
CHANGED
|
@@ -28,7 +28,7 @@ def plot_volatility_smile(x_domain: np.ndarray,
|
|
|
28
28
|
Plot volatility smile for a single expiry.
|
|
29
29
|
|
|
30
30
|
Parameters:
|
|
31
|
-
- x_domain: Array of x-axis values
|
|
31
|
+
- x_domain: Array of x-axis values in the specified domain
|
|
32
32
|
- iv_array: Implied volatility values
|
|
33
33
|
- option_chain: Optional market data for comparison
|
|
34
34
|
- maturity: Maturity name for filtering market data
|
|
@@ -37,8 +37,6 @@ def plot_volatility_smile(x_domain: np.ndarray,
|
|
|
37
37
|
Returns:
|
|
38
38
|
- Plotly figure
|
|
39
39
|
"""
|
|
40
|
-
fig = go.Figure()
|
|
41
|
-
|
|
42
40
|
# Map domain types to axis labels
|
|
43
41
|
domain_labels = {
|
|
44
42
|
'log_moneyness': 'Log Moneyness',
|
|
@@ -47,6 +45,8 @@ def plot_volatility_smile(x_domain: np.ndarray,
|
|
|
47
45
|
'delta': 'Call Delta'
|
|
48
46
|
}
|
|
49
47
|
|
|
48
|
+
fig = go.Figure()
|
|
49
|
+
|
|
50
50
|
# Add model curve
|
|
51
51
|
fig.add_trace(
|
|
52
52
|
go.Scatter(
|
|
@@ -63,37 +63,20 @@ def plot_volatility_smile(x_domain: np.ndarray,
|
|
|
63
63
|
maturity_data = option_chain[option_chain['maturity_name'] == maturity]
|
|
64
64
|
|
|
65
65
|
if not maturity_data.empty:
|
|
66
|
-
#
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
# For delta, we'd need more complex conversion - skip market data for this domain
|
|
77
|
-
market_x = None
|
|
78
|
-
|
|
79
|
-
# Add bid and ask IVs if the domain type allows
|
|
80
|
-
if domain_type != 'delta' and market_x is not None:
|
|
81
|
-
for iv_type in ['bid_iv', 'ask_iv']:
|
|
82
|
-
if iv_type in maturity_data.columns:
|
|
83
|
-
fig.add_trace(
|
|
84
|
-
go.Scatter(
|
|
85
|
-
x=market_x,
|
|
86
|
-
y=maturity_data[iv_type] * 100, # Convert to percentage
|
|
87
|
-
mode='markers',
|
|
88
|
-
name=iv_type.replace('_', ' ').upper(),
|
|
89
|
-
marker=dict(size=8, symbol='circle', opacity=0.7)
|
|
90
|
-
)
|
|
66
|
+
# Add bid and ask IVs if available
|
|
67
|
+
for iv_type in ['bid_iv', 'ask_iv']:
|
|
68
|
+
if iv_type in maturity_data.columns:
|
|
69
|
+
fig.add_trace(
|
|
70
|
+
go.Scatter(
|
|
71
|
+
x=maturity_data['log_moneyness'],
|
|
72
|
+
y=maturity_data[iv_type] * 100, # Convert to percentage
|
|
73
|
+
mode='markers',
|
|
74
|
+
name=iv_type.replace('_', ' ').upper(),
|
|
75
|
+
marker=dict(size=8, symbol='circle', opacity=0.7)
|
|
91
76
|
)
|
|
77
|
+
)
|
|
92
78
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
# Update layout with DTE
|
|
96
|
-
title = f'Vol Smile for {maturity} (DTE: {dte_value:.1f})'
|
|
79
|
+
title = f'Vol Smile for {maturity} (DTE: {maturity_data["dtm"].iloc[0]:.1f})'
|
|
97
80
|
else:
|
|
98
81
|
title = f'Vol Smile for {maturity}'
|
|
99
82
|
else:
|
|
@@ -165,8 +148,8 @@ def plot_raw_parameters(fit_results: pd.DataFrame) -> go.Figure:
|
|
|
165
148
|
maturity_names = fit_results.index
|
|
166
149
|
|
|
167
150
|
# Create hover text with maturity info
|
|
168
|
-
tick_labels = [f"{m} (DTE: {fit_results.loc[m, 'dtm']:.1f}"
|
|
169
|
-
|
|
151
|
+
tick_labels = [f"{m} (DTE: {fit_results.loc[m, 'dtm']:.1f}, YTE: {fit_results.loc[m, 'ytm']:.4f})"
|
|
152
|
+
for m in maturity_names]
|
|
170
153
|
|
|
171
154
|
# Plot each parameter
|
|
172
155
|
for i, param in enumerate(param_names):
|
|
@@ -198,8 +181,7 @@ def plot_raw_parameters(fit_results: pd.DataFrame) -> go.Figure:
|
|
|
198
181
|
fig.update_layout(
|
|
199
182
|
title='Raw SVI Parameters Across Expiries',
|
|
200
183
|
template='plotly_dark',
|
|
201
|
-
showlegend=False
|
|
202
|
-
height=800
|
|
184
|
+
showlegend=False
|
|
203
185
|
)
|
|
204
186
|
|
|
205
187
|
return fig
|
|
@@ -231,7 +213,7 @@ def plot_jw_parameters(fit_results: pd.DataFrame) -> go.Figure:
|
|
|
231
213
|
|
|
232
214
|
# Create hover text with maturity info
|
|
233
215
|
tick_labels = [f"{m} (DTE: {fit_results.loc[m, 'dtm']:.1f}, YTE: {fit_results.loc[m, 'ytm']:.4f})"
|
|
234
|
-
|
|
216
|
+
for m in maturity_names]
|
|
235
217
|
|
|
236
218
|
# Plot each parameter
|
|
237
219
|
for i, param in enumerate(param_names):
|
|
@@ -263,8 +245,7 @@ def plot_jw_parameters(fit_results: pd.DataFrame) -> go.Figure:
|
|
|
263
245
|
fig.update_layout(
|
|
264
246
|
title='Jump-Wing Parameters Across Expiries',
|
|
265
247
|
template='plotly_dark',
|
|
266
|
-
showlegend=False
|
|
267
|
-
height=800
|
|
248
|
+
showlegend=False
|
|
268
249
|
)
|
|
269
250
|
|
|
270
251
|
return fig
|
|
@@ -335,8 +316,7 @@ def plot_fit_performance(fit_results: pd.DataFrame) -> go.Figure:
|
|
|
335
316
|
fig.update_layout(
|
|
336
317
|
title='Model Fitting Accuracy Statistics',
|
|
337
318
|
template='plotly_dark',
|
|
338
|
-
showlegend=False
|
|
339
|
-
height=700
|
|
319
|
+
showlegend=False
|
|
340
320
|
)
|
|
341
321
|
|
|
342
322
|
return fig
|
|
@@ -381,53 +361,31 @@ def plot_3d_surface(x_surface: Dict[str, np.ndarray],
|
|
|
381
361
|
# Default to sequential values
|
|
382
362
|
maturity_values = list(range(len(maturity_names)))
|
|
383
363
|
|
|
384
|
-
#
|
|
385
|
-
|
|
386
|
-
if domain_type in ['log_moneyness', 'moneyness']:
|
|
387
|
-
# Create mesh grid
|
|
388
|
-
X, Y = np.meshgrid(list(x_surface.values())[0], maturity_values)
|
|
389
|
-
Z = np.array([iv_surface[m] * 100 for m in maturity_names]) # Convert to percentage
|
|
390
|
-
|
|
391
|
-
# Create figure
|
|
392
|
-
fig = go.Figure(data=[
|
|
393
|
-
go.Surface(
|
|
394
|
-
z=Z,
|
|
395
|
-
x=X,
|
|
396
|
-
y=Y,
|
|
397
|
-
colorscale=custom_blue_scale,
|
|
398
|
-
contours_z=dict(
|
|
399
|
-
show=True,
|
|
400
|
-
usecolormap=True,
|
|
401
|
-
highlightcolor="#0080FF",
|
|
402
|
-
project_z=True
|
|
403
|
-
)
|
|
404
|
-
)
|
|
405
|
-
])
|
|
364
|
+
# Create 3D surface using lines for each maturity
|
|
365
|
+
fig = go.Figure()
|
|
406
366
|
|
|
407
|
-
#
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
#
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
name=maturity
|
|
430
|
-
))
|
|
367
|
+
# Add a line for each maturity
|
|
368
|
+
for i, maturity in enumerate(maturity_names):
|
|
369
|
+
x_values = x_surface[maturity]
|
|
370
|
+
z_values = iv_surface[maturity] * 100 # Convert to percentage
|
|
371
|
+
y_values = np.full_like(x_values, maturity_values[i])
|
|
372
|
+
|
|
373
|
+
# Color based on maturity (blue to light blue gradient)
|
|
374
|
+
color_intensity = i / max(1, len(maturity_names) - 1)
|
|
375
|
+
color = f'rgb({int(30 + 170*color_intensity)}, {int(120 + 80*color_intensity)}, {int(220 - 120*color_intensity)})'
|
|
376
|
+
|
|
377
|
+
# Add trace
|
|
378
|
+
fig.add_trace(go.Scatter3d(
|
|
379
|
+
x=x_values,
|
|
380
|
+
y=y_values,
|
|
381
|
+
z=z_values,
|
|
382
|
+
mode='lines',
|
|
383
|
+
name=maturity,
|
|
384
|
+
line=dict(
|
|
385
|
+
color=color,
|
|
386
|
+
width=5
|
|
387
|
+
)
|
|
388
|
+
))
|
|
431
389
|
|
|
432
390
|
# Update layout
|
|
433
391
|
fig.update_layout(
|
|
@@ -436,12 +394,7 @@ def plot_3d_surface(x_surface: Dict[str, np.ndarray],
|
|
|
436
394
|
scene=dict(
|
|
437
395
|
xaxis_title=domain_labels.get(domain_type, 'X Domain'),
|
|
438
396
|
yaxis_title='Days to Expiry',
|
|
439
|
-
zaxis_title='Implied Volatility (%)'
|
|
440
|
-
aspectmode='manual',
|
|
441
|
-
aspectratio=dict(x=1.5, y=1, z=1),
|
|
442
|
-
camera=dict(
|
|
443
|
-
eye=dict(x=1.5, y=-1.5, z=1)
|
|
444
|
-
)
|
|
397
|
+
zaxis_title='Implied Volatility (%)'
|
|
445
398
|
),
|
|
446
399
|
margin=dict(l=65, r=50, b=65, t=90)
|
|
447
400
|
)
|
voly/core/fit.py
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
voly/__init__.py,sha256=8xyDk7rFCn_MOD5hxuv5cxxKZvBVRiSIM7TgaMPpwpw,211
|
|
2
|
-
voly/client.py,sha256=
|
|
2
|
+
voly/client.py,sha256=aH9pvH99Y4vp7HRizxnMt6fDs0imyd3Tc7JX-mmeklw,20845
|
|
3
3
|
voly/exceptions.py,sha256=PBsbn1vNMvKcCJwwJ4lBO6glD85jo1h2qiEmD7ArAjs,92
|
|
4
4
|
voly/formulas.py,sha256=wSbGAH6GuQThT9QyQY4Ud2eUf9fo1YFHglUmP6fNris,11871
|
|
5
5
|
voly/models.py,sha256=LXXIlpXZQEfXTuCngxC8Hd3bWtw6wdXDCSGxTLmHM-c,3659
|
|
6
6
|
voly/core/__init__.py,sha256=bu6fS2I1Pj9fPPnl-zY3L7NqrZSY5Zy6NY2uMUvdhKs,183
|
|
7
|
-
voly/core/charts.py,sha256=
|
|
7
|
+
voly/core/charts.py,sha256=EQzGohu2NabNCnD7bUskhRG1uF9-7_AfDl3xdxZ2yZ4,27103
|
|
8
8
|
voly/core/data.py,sha256=e8qBArubNqPkrfuIYB_q2WhRf7TKzA4Z3FhMC-xyLEE,8862
|
|
9
|
-
voly/core/fit.py,sha256=
|
|
9
|
+
voly/core/fit.py,sha256=Zi-LlIobYec8spdJ4uk1g69XQPofWusAAQszugF5QkM,9255
|
|
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.74.dist-info/LICENSE,sha256=wcHIVbE12jfcBOai_wqBKY6xvNQU5E909xL1zZNq_2Q,1065
|
|
15
|
+
voly-0.0.74.dist-info/METADATA,sha256=MqjvGpGORU71xnNLZJJVAYflEMDS6gWcIOWXLvCr1Eo,4092
|
|
16
|
+
voly-0.0.74.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
|
17
|
+
voly-0.0.74.dist-info/top_level.txt,sha256=ZfLw2sSxF-LrKAkgGjOmeTcw6_gD-30zvtdEY5W4B7c,5
|
|
18
|
+
voly-0.0.74.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|