"""Exact mathematical illustrations for Rough volatility and regularity structures. Inputs are illustrative constants, not fitted market parameters. No market data, random numbers, strategy rules or external services are used. Python 3.10+. JSON calculations use the standard library. Rendering figures also requires matplotlib. Run: python rough_volatility_calculations.py --output results.json python rough_volatility_calculations.py --output results.json --figures figures """ from __future__ import annotations import argparse import json import math from pathlib import Path def effective_hurst(h: float, u: float, noise_ratio: float) -> float: if not (0 < h <= 0.5 and u > 0 and noise_ratio >= 0): raise ValueError('Invalid Hurst, lag or noise ratio') signal = u ** (2 * h) return h * signal / (signal + noise_ratio) def interpolation_mean(h: float, n: int, horizon: float = 1.0) -> float: if not (0 < h <= 0.5 and n >= 1 and int(n) == n and horizon > 0): raise ValueError('Invalid Hurst, grid size or horizon') delta = horizon / n return horizon * math.sqrt(2 * h) / ((h + 0.5) * (h + 1.5)) * delta ** (h - 0.5) def calculate() -> dict: lags = [2 ** (-5 + 10 * i / 240) for i in range(241)] noise = [{'noise_ratio': c, 'apparent_h': [effective_hurst(0.5, u, c) for u in lags]} for c in (0.0, 0.1, 1.0)] grids = [2 ** i for i in range(2, 13)] corrections = [{'h': h, 'uncorrected_mean': [interpolation_mean(h, n) for n in grids]} for h in (0.1, 0.25, 0.5)] checks = { 'noise_example_h_equals_0_1': math.isclose(effective_hurst(0.5, 0.25, 1.0), 0.1), 'brownian_correction_equals_half_horizon': all(math.isclose(interpolation_mean(0.5, n, 2.0), 1.0) for n in grids), 'noise_free_slope': all(math.isclose(effective_hurst(0.5, u, 0), 0.5) for u in lags), 'all_numbers_finite': all(math.isfinite(x) for series in noise for x in series['apparent_h']), 'refinement_ratio_h_0_1': math.isclose(interpolation_mean(0.1, 128) / interpolation_mean(0.1, 64), 2 ** 0.4), } if not all(checks.values()): raise AssertionError('Analytical checks failed') return { 'status': 'passed', 'input_origin': 'Invented constants; exact mathematical expectations. No market observations or random draws.', 'noise_model': {'latent_h': 0.5, 'relative_lag': lags, 'curves': noise, 'highlight': {'relative_lag': 0.25, 'noise_ratio': 1.0, 'apparent_h': 0.1}}, 'interpolation_model': {'horizon': 1.0, 'number_of_cells': grids, 'curves': corrections, 'boundary': 'Piecewise-linear Brownian interpolation; causal convolution from time zero.'}, 'ito_linear_variance_at_unit_horizon': {str(h): 1 / (2 * h + 1) for h in (0.1, 0.25, 0.5)}, 'checks': checks, 'convergence_experiment': 'Not performed. Mean identities alone do not establish convergence.', } def plot(result: dict, destination: Path) -> None: import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt destination.mkdir(parents=True, exist_ok=True) plt.rcParams.update({'font.family': 'DejaVu Sans', 'font.size': 12, 'svg.fonttype': 'path', 'svg.hashsalt': 'rough-volatility-v01', 'axes.edgecolor': '#b5c2c9', 'axes.labelcolor': '#243d4d', 'text.color': '#243d4d', 'xtick.color': '#526773', 'ytick.color': '#526773', 'axes.spines.top': False, 'axes.spines.right': False}) for mobile in (False, True): width, height = ((4.6, 4.5) if mobile else (9, 4.9)) plt.rcParams['font.size'] = 12.5 if mobile else 12 suffix = '-mobile' if mobile else '' fig, ax = plt.subplots(figsize=(width, height), layout='constrained') for series, color, style, label in zip(result['noise_model']['curves'], ['#9eabb3', '#327b83', '#233f5a'], ['--', '-', '-'], ['No observation noise', 'Noise ratio 0.1', 'Noise ratio 1']): ax.plot(result['noise_model']['relative_lag'], series['apparent_h'], color=color, linestyle=style, linewidth=2.5, label=label) ax.set_xscale('log', base=2) ax.set_xticks([0.0625, 0.25, 1, 4, 16], ['1/16', '1/4', '1', '4', '16']) ax.set(xlabel='Relative lag, u', ylabel='Apparent exponent', ylim=(0, 0.56)) ax.grid(axis='y', color='#e1e7e9', linewidth=0.7) ax.scatter([0.25], [0.1], color='#a36839', zorder=5, s=40) ax.annotate('0.10 at u = 1/4', xy=(0.25, 0.1), xytext=(0.12, 0.23), fontsize=10.5, color='#805027', arrowprops={'arrowstyle': '-', 'color': '#a36839'}) ax.legend(loc='lower right', frameon=False, fontsize=10.5) fig.savefig(destination / f'noise{suffix}.svg', metadata={'Date': None, 'Creator': 'PSIM mathematical illustrations'}) fig.savefig(destination / f'noise{suffix}.png', dpi=150) plt.close(fig) fig, ax = plt.subplots(figsize=(width, height), layout='constrained') for series, color, style in zip(result['interpolation_model']['curves'], ['#233f5a', '#327b83', '#9eabb3'], ['-', '-', '--']): ax.plot(result['interpolation_model']['number_of_cells'], series['uncorrected_mean'], color=color, linestyle=style, linewidth=2.5, label=f"H = {series['h']}") ax.set_xscale('log', base=2) ax.set_yscale('log', base=2) ax.set_xticks([4, 16, 64, 256, 1024, 4096], ['4', '16', '64', '256', '1,024', '4,096']) ax.set_yticks([0.5, 1, 2, 4, 8, 16], ['0.5', '1', '2', '4', '8', '16']) ax.set(xlabel='Number of grid cells, N', ylabel='Uncorrected mean', ylim=(0.4, 17)) ax.grid(axis='y', color='#e1e7e9', linewidth=0.7) ax.legend(loc='upper left', frameon=False, fontsize=10.5) if mobile: ax.set_xticks([4, 16, 64, 256, 1024, 4096], ['4', '16', '64', '256', '1k', '4k']) ax.tick_params(axis='x', labelsize=11) fig.savefig(destination / f'correction{suffix}.svg', metadata={'Date': None, 'Creator': 'PSIM mathematical illustrations'}) fig.savefig(destination / f'correction{suffix}.png', dpi=150) plt.close(fig) if __name__ == '__main__': parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--output', type=Path, default=Path('rough_volatility_results.json')) parser.add_argument('--figures', type=Path) args = parser.parse_args() result = calculate() if args.figures: plot(result, args.figures) args.output.parent.mkdir(parents=True, exist_ok=True) args.output.write_text(json.dumps(result, indent=2) + '\n', encoding='utf-8') print(json.dumps({'status': result['status'], 'checks': len(result['checks'])}))