|
1 | | -# ml/evaluate.py |
| 1 | +""" |
| 2 | +Evaluating HedgeNet. |
| 3 | +
|
| 4 | +This module contains implementation of HedgeNet evaluation pipeline. |
| 5 | +""" |
| 6 | + |
2 | 7 | import torch |
3 | | -import numpy as np |
| 8 | + |
4 | 9 | from ml.config import GBMConfig, HedgingConfig, StressTestConfig |
5 | | -from ml.sim.gbm import simulate_gbm |
| 10 | +from ml.metrics.pnl import compute_pnl_with_tx |
6 | 11 | from ml.models.hedge_net import HedgeNet |
7 | | -from ml.metrics.pnl import compute_pnl_with_tx, decompose_pnl |
| 12 | +from ml.sim.gbm import simulate_gbm |
8 | 13 |
|
9 | | -def load_model(hidden_dim, path="hedge_net_tx.pth", device="cpu"): |
| 14 | + |
| 15 | +def load_model(hidden_dim, path="artifacts/hedge_net_tx.pth", device="cpu"): |
| 16 | + """Load HedgeNet model from the file.""" |
10 | 17 | net = HedgeNet(hidden_dim).to(device) |
11 | 18 | net.load_state_dict(torch.load(path, weights_only=True)) |
12 | 19 | net.eval() |
13 | 20 | return net |
14 | 21 |
|
15 | | -def prepare_inputs_for_model(S, K, T, M, device='cpu'): |
16 | | - t_grid = torch.linspace(0, T - T/M, M, device=device) |
| 22 | + |
| 23 | +def prepare_inputs_for_model(S, K, T, M, device="cpu"): |
| 24 | + """Prepare inputs for HedgeNet evaluation.""" |
| 25 | + t_grid = torch.linspace(0, T - T / M, M, device=device) |
17 | 26 | tau = T - t_grid |
18 | 27 | N = S.size(0) |
19 | 28 | tau_batch = tau.unsqueeze(0).expand(N, -1).reshape(-1) |
20 | 29 | moneyness_batch = (S[:, :-1] / K).reshape(-1) |
21 | 30 | return tau_batch, moneyness_batch, N, M |
22 | 31 |
|
| 32 | + |
23 | 33 | def run_stress_test(): |
| 34 | + """Run some testing scenarios on hedging with HedgeNet.""" |
24 | 35 | base_gbm = GBMConfig() |
25 | 36 | base_hedge = HedgingConfig() |
26 | 37 | stress_cfg = StressTestConfig() |
27 | 38 |
|
28 | 39 | net = load_model(base_hedge.hidden_dim, device=base_hedge.device) |
29 | 40 |
|
30 | | - results = { |
31 | | - 'sigma': [], |
32 | | - 'lambda_tx': [], |
33 | | - 'M': [], |
34 | | - 'mean_abs_pnl': [], |
35 | | - 'std_pnl': [] |
36 | | - } |
| 41 | + results = {"sigma": [], "lambda_tx": [], "M": [], "mean_abs_pnl": [], "std_pnl": []} |
37 | 42 |
|
38 | 43 | # Vary sigma |
39 | 44 | for sigma in stress_cfg.sigma_vals: |
40 | 45 | gbm = GBMConfig(S0=base_gbm.S0, sigma=sigma, T=base_gbm.T, N=5000, M=base_gbm.M) |
41 | 46 | S = simulate_gbm(**gbm.__dict__, device=base_hedge.device).float() |
42 | | - tau_flat, moneyness_flat, N, M = prepare_inputs_for_model(S, base_hedge.K, gbm.T, gbm.M) |
| 47 | + tau_flat, moneyness_flat, N, M = prepare_inputs_for_model( |
| 48 | + S, base_hedge.K, gbm.T, gbm.M |
| 49 | + ) |
43 | 50 | with torch.no_grad(): |
44 | 51 | phi_flat = net(tau_flat, moneyness_flat) |
45 | 52 | phi = phi_flat.reshape(N, M) |
46 | 53 | pnl = compute_pnl_with_tx(S, base_hedge.K, phi, base_hedge.lambda_tx) |
47 | | - results['sigma'].append(sigma) |
48 | | - results['lambda_tx'].append(base_hedge.lambda_tx) |
49 | | - results['M'].append(gbm.M) |
50 | | - results['mean_abs_pnl'].append(pnl.abs().mean().item()) |
51 | | - results['std_pnl'].append(pnl.std().item()) |
| 54 | + results["sigma"].append(sigma) |
| 55 | + results["lambda_tx"].append(base_hedge.lambda_tx) |
| 56 | + results["M"].append(gbm.M) |
| 57 | + results["mean_abs_pnl"].append(pnl.abs().mean().item()) |
| 58 | + results["std_pnl"].append(pnl.std().item()) |
52 | 59 |
|
53 | 60 | # Vary lambda_tx |
54 | 61 | for lam in stress_cfg.lambda_vals: |
55 | 62 | S = simulate_gbm(**base_gbm.__dict__, device=base_hedge.device).float() |
56 | | - tau_flat, moneyness_flat, N, M = prepare_inputs_for_model(S, base_hedge.K, base_gbm.T, base_gbm.M) |
| 63 | + tau_flat, moneyness_flat, N, M = prepare_inputs_for_model( |
| 64 | + S, base_hedge.K, base_gbm.T, base_gbm.M |
| 65 | + ) |
57 | 66 | with torch.no_grad(): |
58 | 67 | phi_flat = net(tau_flat, moneyness_flat) |
59 | 68 | phi = phi_flat.reshape(N, M) |
60 | 69 | pnl = compute_pnl_with_tx(S, base_hedge.K, phi, lam) |
61 | | - results['sigma'].append(base_gbm.sigma) |
62 | | - results['lambda_tx'].append(lam) |
63 | | - results['M'].append(base_gbm.M) |
64 | | - results['mean_abs_pnl'].append(pnl.abs().mean().item()) |
65 | | - results['std_pnl'].append(pnl.std().item()) |
| 70 | + results["sigma"].append(base_gbm.sigma) |
| 71 | + results["lambda_tx"].append(lam) |
| 72 | + results["M"].append(base_gbm.M) |
| 73 | + results["mean_abs_pnl"].append(pnl.abs().mean().item()) |
| 74 | + results["std_pnl"].append(pnl.std().item()) |
66 | 75 |
|
67 | 76 | # Vary M (rebalancing frequency) |
68 | 77 | for M in stress_cfg.M_vals: |
69 | 78 | gbm = GBMConfig(S0=base_gbm.S0, sigma=base_gbm.sigma, T=base_gbm.T, N=5000, M=M) |
70 | 79 | S = simulate_gbm(**gbm.__dict__, device=base_hedge.device).float() |
71 | | - tau_flat, moneyness_flat, N, M_actual = prepare_inputs_for_model(S, base_hedge.K, gbm.T, gbm.M) |
| 80 | + tau_flat, moneyness_flat, N, M_actual = prepare_inputs_for_model( |
| 81 | + S, base_hedge.K, gbm.T, gbm.M |
| 82 | + ) |
72 | 83 | with torch.no_grad(): |
73 | 84 | phi_flat = net(tau_flat, moneyness_flat) |
74 | 85 | phi = phi_flat.reshape(N, M_actual) |
75 | 86 | pnl = compute_pnl_with_tx(S, base_hedge.K, phi, base_hedge.lambda_tx) |
76 | | - results['sigma'].append(base_gbm.sigma) |
77 | | - results['lambda_tx'].append(base_hedge.lambda_tx) |
78 | | - results['M'].append(M) |
79 | | - results['mean_abs_pnl'].append(pnl.abs().mean().item()) |
80 | | - results['std_pnl'].append(pnl.std().item()) |
| 87 | + results["sigma"].append(base_gbm.sigma) |
| 88 | + results["lambda_tx"].append(base_hedge.lambda_tx) |
| 89 | + results["M"].append(M) |
| 90 | + results["mean_abs_pnl"].append(pnl.abs().mean().item()) |
| 91 | + results["std_pnl"].append(pnl.std().item()) |
81 | 92 |
|
82 | 93 | return results |
83 | | - |
84 | | - |
|
0 commit comments