Skip to content

Commit

Permalink
Release/0.14.1 (#392)
Browse files Browse the repository at this point in the history
* BUG: Fix BSAmericanBinaryOption (#366) (#391)

* TEST: Add more tests to BS modules (#366) (#391)

* MAINT: Rename base classes to "Base*" (close #384) (#386)

  * `Instrument`, `Primary`, `Derivative` are deprecated. Use `Base*` instead.

* MAINT: Miscellaneous maintainances (#385) (#387) (#388) (#389)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <[email protected]>
  • Loading branch information
3 people authored Nov 9, 2021
1 parent 74ead55 commit a14df77
Show file tree
Hide file tree
Showing 44 changed files with 1,268 additions and 392 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
poetry.lock
docs/source/generated/
examples/output/
examples/output/.gitkeep

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
11 changes: 6 additions & 5 deletions docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,26 @@
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= poetry run sphinx-build
SPHINXAUTOBUILD ?= poetry run sphinx-autobuild
SPHINXBUILD ?= sphinx-build
SPHINXAUTOBUILD ?= sphinx-autobuild
SOURCEDIR = source
BUILDDIR = build
RUN = poetry run

# Put it first so that "make" without argument is like "make help".
help:
$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
$(RUN) $(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
$(RUN) $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

clean:
echo "Removing everything under 'build' and 'source/generated'.."
rm -rf $(BUILDDIR)/html/ $(BUILDDIR)/doctrees $(SOURCEDIR)/generated

livehtml:
$(SPHINXAUTOBUILD) "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) --open-browser $(O)
$(RUN) $(SPHINXAUTOBUILD) "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) --open-browser $(O)
8 changes: 4 additions & 4 deletions docs/source/instruments.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ Base Class
:nosignatures:
:template: classtemplate.rst

instruments.Instrument
instruments.BaseInstrument
instruments.BasePrimary
instruments.BaseDerivative
instruments.BaseOption

Primary Instruments
-------------------
Expand All @@ -24,7 +27,6 @@ Primary Instruments
:nosignatures:
:template: classtemplate.rst

instruments.Primary
instruments.BrownianStock
instruments.HestonStock
instruments.CIRRate
Expand All @@ -37,8 +39,6 @@ Derivative Instruments
:nosignatures:
:template: classtemplate.rst

instruments.Derivative
instruments.BaseOption
instruments.EuropeanOption
instruments.LookbackOption
instruments.EuropeanBinaryOption
Expand Down
20 changes: 10 additions & 10 deletions docs/source/notes/instrument_attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
Instrument dtype and device
===========================

The attributes :attr:`Primary.dtype` and :attr:`Primary.device` specify
The attributes ``dtype`` and ``device`` of a primary instrument specify
the dtype and devices with which the buffers of the instrument are represented.
The attributes :attr:`Derivative.dtype` and :attr:`Derivative.device`
The attributes ``dtype`` and ``device`` of a derivative instrument
are aliased to the dtype/device of its underlier.

A instrument of specific dtype/device can be constructed by
Expand All @@ -28,7 +28,7 @@ passing a ``torch.dtype`` and/or a ``torch.device`` to a constructor.
tensor([[..., ..., ...],
[..., ..., ...]], device='cuda:0')
The methods :meth:`Primary.to()` and :meth:`Derivative.to()` work as
The methods :meth:`BasePrimary.to()` and :meth:`BaseDerivative.to()` work as
:meth:`torch.nn.Module.to` and cast/move the dtype and device of the instrument
to the desired ones.

Expand All @@ -41,13 +41,13 @@ Instrument.dtype
Primary
^^^^^^^

One can simulate the movement of a ``Primary`` instrument (e.g., :class:`EuropeanOption`)
One can simulate the movement of a primary instrument (e.g., :class:`EuropeanOption`)
to get the associated buffers (e.g., ``spot``).

The simulation will be performed with a :class:`torch.dtype`
specified by :attr:`Primary.dtype`.
specified by :attr:`BasePrimary.dtype`.
The default dtype is the global default (see :func:`torch.set_default_tensor_type()`).
The :meth:`Primary.to()` method modifies the instrument so that
The :meth:`BasePrimary.to()` method modifies the instrument so that
subsequent simulations will be performed with the desired dtype.

.. code:: python
Expand All @@ -74,7 +74,7 @@ to the desired dtype.
Derivative
^^^^^^^^^^

If one calls :meth:`Derivative.to()`, its underlier gets the desired dtype.
If one calls :meth:`BaseDerivative.to()`, its underlier gets the desired dtype.
As a result, the ``payoff`` also has the same dtype.

.. code:: python
Expand Down Expand Up @@ -102,10 +102,10 @@ Primary
^^^^^^^

The simulation will be performed with a :class:`torch.device`
specified by :attr:`Primary.device`.
specified by :attr:`BasePrimary.device`.
The default device is the current device for the default tensor type
(see :func:`torch.set_default_tensor_type()`).
The :meth:`Primary.to()` method modifies the instument so that
The :meth:`BasePrimary.to()` method modifies the instument so that
subsequent simulations will be performed on the desired device.

.. code:: python
Expand All @@ -127,7 +127,7 @@ to the desired device.
Derivative
^^^^^^^^^^

If one calls :meth:`Derivative.to()`, its underlier gets the desired device.
If one calls :meth:`BaseDerivative.to()`, its underlier gets the desired device.
As a result, the ``payoff`` is also on the same device.

.. code:: python
Expand Down
4 changes: 2 additions & 2 deletions examples/example_knockout.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
import torch
from torch import Tensor

from pfhedge.instruments import BaseDerivative
from pfhedge.instruments import BrownianStock
from pfhedge.instruments import Derivative
from pfhedge.instruments import EuropeanOption

derivative = EuropeanOption(BrownianStock(cost=1e-4))

def knockout(derivative: Derivative, payoff: Tensor) -> Tensor:
def knockout(derivative: BaseDerivative, payoff: Tensor) -> Tensor:
max = derivative.ul().spot.max(-1).values
return payoff.where(max <= 1.1, torch.zeros_like(max))

Expand Down
2 changes: 1 addition & 1 deletion examples/example_no_transaction_band.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class NoTransactionBandNet(Module):
The `forward` method returns the next hedge ratio.
Args:
derivative (pfhedge.instruments.Derivative): The derivative to hedge.
derivative (pfhedge.instruments.BaseDerivative): The derivative to hedge.
Shape:
- Input: :math:`(N, H_{\\text{in}})`, where :math:`(N, H_{\\text{in}})` is the
Expand Down
110 changes: 110 additions & 0 deletions examples/example_plot_american_binary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import sys

import matplotlib.pyplot as plt
import torch

sys.path.append("..")
from pfhedge.nn import BSAmericanBinaryOption

LOG_MONEYNESS_MIN = -0.2
LOG_MONEYNESS_MAX = 0.2
LOG_MONEYNESS_STEPS = 1000
S = torch.linspace(LOG_MONEYNESS_MIN, LOG_MONEYNESS_MAX, LOG_MONEYNESS_STEPS)
VOLATILITY_RANGE = [0.1, 0.2, 0.3]
VOLATILITY_DEFAULT = 0.1
TIME_TO_MATURITY_RANGE = [0.1, 0.2, 0.3]
TIME_TO_MATURITY_DEFAULT = 0.1


def plot_delta() -> None:
m = BSAmericanBinaryOption()

plt.figure()
for volatility in VOLATILITY_RANGE:
s = S
t = torch.full_like(s, TIME_TO_MATURITY_DEFAULT)
v = torch.full_like(s, volatility)
y = m.delta(s, s, t, v)
plt.plot(s, y, label=f"Volatility={volatility:.1f}")
plt.xlabel("Log moneyness")
plt.ylabel("Delta")
plt.legend()
plt.savefig("./output/american-binary-delta-volatility.png")

plt.figure()
for time_to_maturity in TIME_TO_MATURITY_RANGE:
s = S
t = torch.full_like(s, time_to_maturity)
v = torch.full_like(s, TIME_TO_MATURITY_DEFAULT)
y = m.delta(s, s, t, v)
plt.plot(s, y, label=f"Time to maturity={time_to_maturity:.1f}")
plt.xlabel("Log moneyness")
plt.ylabel("Delta")
plt.legend()
plt.savefig("./output/american-binary-delta-time.png")


def plot_gamma() -> None:
m = BSAmericanBinaryOption()

plt.figure()
for volatility in VOLATILITY_RANGE:
s = S
t = torch.full_like(s, TIME_TO_MATURITY_DEFAULT)
v = torch.full_like(s, volatility)
y = m.gamma(s, s, t, v)
plt.plot(s, y, label=f"Volatility={volatility:.1f}")
plt.xlabel("Log moneyness")
plt.ylabel("Gamma")
plt.legend()
plt.savefig("./output/american-binary-gamma-volatility.png")

plt.figure()
for time_to_maturity in TIME_TO_MATURITY_RANGE:
s = S
t = torch.full_like(s, time_to_maturity)
v = torch.full_like(s, TIME_TO_MATURITY_DEFAULT)
y = m.gamma(s, s, t, v)
plt.plot(s, y, label=f"Time to maturity={time_to_maturity:.1f}")
plt.xlabel("Log moneyness")
plt.ylabel("Gamma")
plt.legend()
plt.savefig("./output/american-binary-gamma-time.png")


def plot_price() -> None:
m = BSAmericanBinaryOption()

plt.figure()
for volatility in VOLATILITY_RANGE:
s = S
t = torch.full_like(s, TIME_TO_MATURITY_DEFAULT)
v = torch.full_like(s, volatility)
y = m.price(s, s, t, v)
plt.plot(s, y, label=f"Volatility={volatility:.1f}")
plt.xlabel("Log moneyness")
plt.ylabel("Price")
plt.legend()
plt.savefig("./output/american-binary-price-volatility.png")

plt.figure()
for time_to_maturity in TIME_TO_MATURITY_RANGE:
s = S
t = torch.full_like(s, time_to_maturity)
v = torch.full_like(s, TIME_TO_MATURITY_DEFAULT)
y = m.price(s, s, t, v)
plt.plot(s, y, label=f"Time to maturity={time_to_maturity:.1f}")
plt.xlabel("Log moneyness")
plt.ylabel("Price")
plt.legend()
plt.savefig("./output/american-binary-price-time.png")


def main():
plot_delta()
plot_gamma()
plot_price()


if __name__ == "__main__":
main()
110 changes: 110 additions & 0 deletions examples/example_plot_european.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import sys

import matplotlib.pyplot as plt
import torch

sys.path.append("..")
from pfhedge.nn import BSEuropeanOption

LOG_MONEYNESS_MIN = -0.2
LOG_MONEYNESS_MAX = 0.2
LOG_MONEYNESS_STEPS = 1000
S = torch.linspace(LOG_MONEYNESS_MIN, LOG_MONEYNESS_MAX, LOG_MONEYNESS_STEPS)
VOLATILITY_RANGE = [0.1, 0.2, 0.3]
VOLATILITY_DEFAULT = 0.1
TIME_TO_MATURITY_RANGE = [0.1, 0.2, 0.3]
TIME_TO_MATURITY_DEFAULT = 0.1


def plot_delta() -> None:
m = BSEuropeanOption()

plt.figure()
for volatility in VOLATILITY_RANGE:
s = S
t = torch.full_like(s, TIME_TO_MATURITY_DEFAULT)
v = torch.full_like(s, volatility)
y = m.delta(s, t, v)
plt.plot(s, y, label=f"Volatility={volatility:.1f}")
plt.xlabel("Log moneyness")
plt.ylabel("Delta")
plt.legend()
plt.savefig("./output/european-delta-volatility.png")

plt.figure()
for time_to_maturity in TIME_TO_MATURITY_RANGE:
s = S
t = torch.full_like(s, time_to_maturity)
v = torch.full_like(s, TIME_TO_MATURITY_DEFAULT)
y = m.delta(s, t, v)
plt.plot(s, y, label=f"Time to maturity={time_to_maturity:.1f}")
plt.xlabel("Log moneyness")
plt.ylabel("Delta")
plt.legend()
plt.savefig("./output/european-delta-time.png")


def plot_gamma() -> None:
m = BSEuropeanOption()

plt.figure()
for volatility in VOLATILITY_RANGE:
s = S
t = torch.full_like(s, TIME_TO_MATURITY_DEFAULT)
v = torch.full_like(s, volatility)
y = m.gamma(s, t, v)
plt.plot(s, y, label=f"Volatility={volatility:.1f}")
plt.xlabel("Log moneyness")
plt.ylabel("Gamma")
plt.legend()
plt.savefig("./output/european-gamma-volatility.png")

plt.figure()
for time_to_maturity in TIME_TO_MATURITY_RANGE:
s = S
t = torch.full_like(s, time_to_maturity)
v = torch.full_like(s, TIME_TO_MATURITY_DEFAULT)
y = m.gamma(s, t, v)
plt.plot(s, y, label=f"Time to maturity={time_to_maturity:.1f}")
plt.xlabel("Log moneyness")
plt.ylabel("Gamma")
plt.legend()
plt.savefig("./output/european-gamma-time.png")


def plot_price() -> None:
m = BSEuropeanOption()

plt.figure()
for volatility in VOLATILITY_RANGE:
s = S
t = torch.full_like(s, TIME_TO_MATURITY_DEFAULT)
v = torch.full_like(s, volatility)
y = m.price(s, t, v)
plt.plot(s, y, label=f"Volatility={volatility:.1f}")
plt.xlabel("Log moneyness")
plt.ylabel("Price")
plt.legend()
plt.savefig("./output/european-price-volatility.png")

plt.figure()
for time_to_maturity in TIME_TO_MATURITY_RANGE:
s = S
t = torch.full_like(s, time_to_maturity)
v = torch.full_like(s, TIME_TO_MATURITY_DEFAULT)
y = m.price(s, t, v)
plt.plot(s, y, label=f"Time to maturity={time_to_maturity:.1f}")
plt.xlabel("Log moneyness")
plt.ylabel("Price")
plt.legend()
plt.savefig("./output/european-price-time.png")


def main():
plot_delta()
plot_gamma()
plot_price()


if __name__ == "__main__":
main()
Loading

0 comments on commit a14df77

Please sign in to comment.