def test_dtype(self, dtype): liability = EuropeanOption(BrownianStock(dtype=dtype)) assert liability.dtype == dtype liability.simulate() assert liability.payoff().dtype == dtype liability = EuropeanOption(BrownianStock()).to(dtype=dtype) liability.simulate() assert liability.payoff().dtype == dtype
def test_repr(self): liability = EuropeanOption(BrownianStock(), maturity=1.0) expect = "EuropeanOption(BrownianStock(...), maturity=1.00e+00)" assert repr(liability) == expect liability = EuropeanOption(BrownianStock(), maturity=1.0, call=False) expect = "EuropeanOption(BrownianStock(...), call=False, maturity=1.00e+00)" assert repr(liability) == expect liability = EuropeanOption(BrownianStock(), maturity=1.0, strike=2.0) expect = "EuropeanOption(BrownianStock(...), strike=2.0, maturity=1.00e+00)" assert repr(liability) == expect
def test_repr(self): m = BSEuropeanOption() assert repr(m) == "BSEuropeanOption()" liability = EuropeanOption(BrownianStock(), strike=1.1, call=False) m = BSEuropeanOption(liability) assert repr(m) == "BSEuropeanOption(call=False, strike=1.1)"
def test_shape(self): torch.distributions.Distribution.set_default_validate_args(False) deriv = EuropeanOption(BrownianStock()) N = 2 M_1 = 5 M_2 = 6 H_in = 3 x = torch.empty((N, M_1, M_2, H_in)) m = Hedger(MultiLayerPerceptron(), ["zero"]) assert m(x).size() == torch.Size((N, M_1, M_2, 1)) model = BlackScholes(deriv) m = Hedger(model, model.features()) x = torch.empty((N, M_1, M_2, len(model.features()))) assert m(x).size() == torch.Size((N, M_1, M_2, 1)) model = WhalleyWilmott(deriv) m = Hedger(model, model.features()) x = torch.empty((N, M_1, M_2, len(model.features()))) assert m(x).size() == torch.Size((N, M_1, M_2, 1)) model = Naked() m = Hedger(model, ["zero"]) x = torch.empty((N, M_1, M_2, 10)) assert m(x).size() == torch.Size((N, M_1, M_2, 1))
def test_repr(self): hedger = Hedger(Linear(2, 1), ["moneyness", "expiry_time"]) assert repr(hedger) == ( "Hedger(\n" " features=['moneyness', 'expiry_time'],\n" " (model): Linear(in_features=2, out_features=1, bias=True)\n" " (criterion): EntropicRiskMeasure()\n" ")") liability = EuropeanOption(BrownianStock()) model = BlackScholes(liability) hedger = Hedger(model, model.features()) assert repr(hedger) == ( "Hedger(\n" " features=['log_moneyness', 'expiry_time', 'volatility'],\n" " (model): BSEuropeanOption()\n" " (criterion): EntropicRiskMeasure()\n" ")") hedger = Hedger(naked, ["moneyness", "expiry_time"]) assert repr(hedger) == ("Hedger(\n" " model=naked,\n" " features=['moneyness', 'expiry_time'],\n" " (criterion): EntropicRiskMeasure()\n" ")")
def test_init(self): liability = EuropeanOption(BrownianStock()) m = BlackScholes(liability) assert m.__class__ == BSEuropeanOption assert m.strike == 1.0 assert m.call liability = EuropeanOption(BrownianStock(), strike=2.0, call=False) m = BlackScholes(liability) assert m.__class__ == BSEuropeanOption assert m.strike == 2.0 assert not m.call liability = LookbackOption(BrownianStock()) m = BlackScholes(liability) assert m.__class__ == BSLookbackOption assert m.strike == 1.0 assert m.call
def test_compute_loss(self): torch.manual_seed(42) deriv = EuropeanOption(BrownianStock()) hedger = Hedger(Naked(), ["log_moneyness", "expiry_time", "volatility"]) result = hedger.compute_loss(deriv) expect = EntropicRiskMeasure()(-deriv.payoff()) assert torch.allclose(result, expect)
def test_parity(self, volatility, strike, maturity, n_paths, init_price): """ Test put-call parity. """ stock = BrownianStock(volatility) co = EuropeanOption(stock, strike=strike, maturity=maturity, call=True) po = EuropeanOption(stock, strike=strike, maturity=maturity, call=False) co.simulate(n_paths=n_paths, init_price=init_price) po.simulate(n_paths=n_paths, init_price=init_price) s = stock.prices[-1, :] c = co.payoff() p = po.payoff() assert ((c - p) == s - strike).all()
def test(self): liability = EuropeanOption(BrownianStock()) liability.underlier.prices = torch.tensor([ [1.0, 2.0, 3.0, 1.0], [1.5, 1.0, 4.0, 1.1], [2.0, 1.0, 5.0, 1.2], [3.0, 1.0, 6.0, 1.3], ]) f = Barrier(2.0, up=True).of(liability) result = f[0] expect = torch.tensor([0.0, 1.0, 1.0, 0.0]).reshape(-1, 1) assert torch.allclose(result, expect) result = f[1] expect = torch.tensor([0.0, 1.0, 1.0, 0.0]).reshape(-1, 1) assert torch.allclose(result, expect) result = f[2] expect = torch.tensor([1.0, 1.0, 1.0, 0.0]).reshape(-1, 1) assert torch.allclose(result, expect) result = f[3] expect = torch.tensor([1.0, 1.0, 1.0, 0.0]).reshape(-1, 1) assert torch.allclose(result, expect) liability = EuropeanOption(BrownianStock()) liability.underlier.prices = torch.tensor([ [3.0, 1.0, 6.0, 1.3], [2.0, 1.0, 5.0, 1.2], [1.5, 1.0, 4.0, 1.1], [1.0, 2.0, 3.0, 1.0], ]) f = Barrier(2.0, up=False).of(liability) result = f[0] expect = torch.tensor([0.0, 1.0, 0.0, 1.0]).reshape(-1, 1) assert torch.allclose(result, expect) result = f[1] expect = torch.tensor([1.0, 1.0, 0.0, 1.0]).reshape(-1, 1) assert torch.allclose(result, expect) result = f[2] expect = torch.tensor([1.0, 1.0, 0.0, 1.0]).reshape(-1, 1) assert torch.allclose(result, expect) result = f[3] expect = torch.tensor([1.0, 1.0, 0.0, 1.0]).reshape(-1, 1) assert torch.allclose(result, expect)
def test_payoff(self): liability = EuropeanOption(BrownianStock(), strike=2.0) liability.underlier.prices = torch.tensor([ [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.9, 2.0, 2.1, 3.0], ]) result = liability.payoff() expect = torch.tensor([0.0, 0.0, 0.1, 1.0]) assert torch.allclose(result, expect)
def test_example(self): from pfhedge import Hedger from pfhedge.instruments import BrownianStock from pfhedge.instruments import EuropeanOption liability = EuropeanOption(BrownianStock()) model = BSEuropeanOption() hedger = Hedger(model, model.features()) price = hedger.price(liability) assert torch.allclose(price, torch.tensor(0.0221), atol=1e-4)
def test_compute_pnl(self): torch.manual_seed(42) deriv = EuropeanOption(BrownianStock()) hedger = Hedger(Naked(), ["zero"]) pnl = hedger.compute_pnl(deriv) payoff = deriv.payoff() assert torch.allclose(pnl, -payoff) result = hedger.compute_pnl(deriv) expect = -deriv.payoff() assert torch.allclose(result, expect)
def test_repr(self): liability = EuropeanOption(BrownianStock()) m = WhalleyWilmott(liability) assert repr(m) == ("WhalleyWilmott(\n" " (bs): BSEuropeanOption()\n" " (clamp): Clamp()\n" ")") liability = EuropeanOption(BrownianStock()) m = WhalleyWilmott(liability, a=2) assert repr(m) == ("WhalleyWilmott(\n" " a=2\n" " (bs): BSEuropeanOption()\n" " (clamp): Clamp()\n" ")") liability = LookbackOption(BrownianStock()) m = WhalleyWilmott(liability) assert repr(m) == ("WhalleyWilmott(\n" " (bs): BSLookbackOption()\n" " (clamp): Clamp()\n" ")")
def test(self, volatility): liability = EuropeanOption(BrownianStock(volatility=volatility)) liability.underlier.prices = torch.arange(1.0, 7.0).reshape(3, 2) f = Volatility().of(liability) result = f[0] expect = torch.full((2, 1), volatility) assert torch.allclose(result, expect) result = f[1] expect = torch.full((2, 1), volatility) assert torch.allclose(result, expect) result = f[2] expect = torch.full((2, 1), volatility) assert torch.allclose(result, expect)
def test_forward(self): m = BSEuropeanOption() x = torch.tensor([0.0, 1.0, 0.2]).reshape(1, -1) result = m(x).item() assert np.isclose(result, 0.5398278962) m = BSEuropeanOption(call=False) x = torch.tensor([0.0, 1.0, 0.2]).reshape(1, -1) result = m(x).item() assert np.isclose(result, -0.4601721) liability = EuropeanOption(BrownianStock(), call=False) m = BSEuropeanOption(liability) x = torch.tensor([0.0, 1.0, 0.2]).reshape(1, -1) result = m(x).item() assert np.isclose(result, -0.4601721)
def test(self): torch.manual_seed(42) liability = EuropeanOption(BrownianStock()) liability.underlier.prices = torch.arange(1.0, 7.0).reshape(3, 2) f = Zero().of(liability) result = f[0] expect = torch.zeros((2, 1)) assert torch.allclose(result, expect) result = f[1] expect = torch.zeros((2, 1)) assert torch.allclose(result, expect) result = f[2] expect = torch.zeros((2, 1)) assert torch.allclose(result, expect)
def test(self): liability = EuropeanOption(BrownianStock()) liability.simulate() module = torch.nn.Linear(2, 1) x1, x2 = Moneyness(), ExpiryTime() f = ModuleOutput(module, [x1, x2]).of(liability) result = f[0] expect = module(torch.cat([x1[0], x2[0]], 1)) assert torch.allclose(result, expect) result = f[1] expect = module(torch.cat([x1[1], x2[1]], 1)) assert torch.allclose(result, expect) result = f[2] expect = module(torch.cat([x1[2], x2[2]], 1)) assert torch.allclose(result, expect)
def test(self): maturity = 3 / 365 dt = 1 / 365 liability = EuropeanOption(BrownianStock(dt=dt), maturity=maturity) liability.underlier.prices = torch.arange(1.0, 7.0).reshape(3, 2) f = ExpiryTime().of(liability) result = f[0] expect = torch.full((2, 1), 3 / 365) assert torch.allclose(result, expect) result = f[1] expect = torch.full((2, 1), 2 / 365) assert torch.allclose(result, expect) result = f[2] expect = torch.full((2, 1), 1 / 365) assert torch.allclose(result, expect)
def test_shape(self): torch.distributions.Distribution.set_default_validate_args(False) deriv = EuropeanOption(BrownianStock()) m = WhalleyWilmott(deriv) N = 10 H_in = len(m.features()) M_1 = 11 M_2 = 12 x = torch.empty((N, H_in)) assert m(x).size() == torch.Size((N, 1)) x = torch.empty((N, M_1, H_in)) assert m(x).size() == torch.Size((N, M_1, 1)) x = torch.empty((N, M_1, M_2, H_in)) assert m(x).size() == torch.Size((N, M_1, M_2, 1))
def test(self, strike): liability = EuropeanOption(BrownianStock(), strike=strike) liability.underlier.prices = torch.arange(1.0, 7.0).reshape(3, 2) # tensor([[1., 2.], # [3., 4.], # [5., 6.]]) f = LogMoneyness().of(liability) result = f[0] expect = torch.tensor([[1.0], [2.0]]) / strike expect = torch.log(expect) assert torch.allclose(result, expect) result = f[1] expect = torch.tensor([[3.0], [4.0]]) / strike expect = torch.log(expect) assert torch.allclose(result, expect) result = f[2] expect = torch.tensor([[5.0], [6.0]]) / strike expect = torch.log(expect) assert torch.allclose(result, expect)
def test(self, volatility): torch.manual_seed(42) liability = EuropeanOption(BrownianStock(volatility)) liability.underlier.prices = torch.arange(1.0, 7.0).reshape(3, 2) hedger = Hedger(Linear(2, 1), ["moneyness", "expiry_time"]) hedger.features = [ feature.of(liability) for feature in hedger.features ] f = PrevHedge().of(liability, hedger) result = f[0] expect = torch.zeros((2, 1)) assert torch.allclose(result, expect) h = hedger(torch.cat([feature[0] for feature in hedger.features], 1)) result = f[1] expect = h.reshape(-1, 1) assert torch.allclose(result, expect) h = hedger(torch.cat([feature[1] for feature in hedger.features], 1)) result = f[2] expect = h.reshape(-1, 1) assert torch.allclose(result, expect)
def test(self, strike): liability = EuropeanOption(BrownianStock(), strike=strike) liability.underlier.prices = torch.tensor([ [1.0, 2.0, 3.0], [2.0, 3.0, 2.0], [1.5, 4.0, 1.0], ]) f = MaxLogMoneyness().of(liability) result = f[0] expect = torch.tensor([[1.0], [2.0], [3.0]]) / strike expect = torch.log(expect) assert torch.allclose(result, expect) result = f[1] expect = torch.tensor([[2.0], [3.0], [3.0]]) / strike expect = torch.log(expect) assert torch.allclose(result, expect) result = f[2] expect = torch.tensor([[2.0], [4.0], [3.0]]) / strike expect = torch.log(expect) assert torch.allclose(result, expect)
import torch sys.path.append("..") from pfhedge import Hedger # noqa: E402 from pfhedge.instruments import BrownianStock # noqa: E402 from pfhedge.instruments import EuropeanOption # noqa: E402 from pfhedge.nn import ExpectedShortfall from pfhedge.nn import MultiLayerPerceptron # noqa: E402 if __name__ == "__main__": torch.manual_seed(42) # Prepare a derivative to hedge deriv = EuropeanOption(BrownianStock(cost=1e-4)) # Expected shortfall with the quantile level of 10% expected_shortfall = ExpectedShortfall(0.1) # Create your hedger model = MultiLayerPerceptron() hedger = Hedger( model, ["log_moneyness", "expiry_time", "volatility", "prev_hedge"], criterion=expected_shortfall, ) # Fit and price hedger.fit(deriv, n_paths=10000, n_epochs=200) price = hedger.price(deriv, n_paths=10000)
def test_dtype(self, dtype): liability = EuropeanOption(BrownianStock()) self.assert_same_dtype(LogMoneyness(), liability, dtype)
def test_dtype(self, dtype): liability = EuropeanOption(BrownianStock()).to(dtype) m = Linear(2, 1).to(liability.dtype) f = ModuleOutput(m, [Moneyness(), ExpiryTime()]) self.assert_same_dtype(f, liability, dtype)
def test_net(): liability = EuropeanOption(BrownianStock(cost=1e-4)) model = MultiLayerPerceptron() hedger = Hedger(model, ["log_moneyness", "expiry_time", "volatility", "prev_hedge"]) _ = hedger.fit(liability, n_paths=100, n_epochs=10) _ = hedger.price(liability)
def test_ww(): liability = EuropeanOption(BrownianStock(cost=1e-4)) model = WhalleyWilmott(liability) hedger = Hedger(model, model.features()) _ = hedger.price(liability)
def test_bs(): liability = EuropeanOption(BrownianStock(cost=1e-4)) model = BlackScholes(liability) hedger = Hedger(model, model.features()) _ = hedger.price(liability)
def test_dtype(self, dtype): liability = EuropeanOption(BrownianStock()) self.assert_same_dtype(Barrier(1.0), liability, dtype)
def test_device(self, device): liability = EuropeanOption(BrownianStock(device=device)) assert liability.device == torch.device(device)