Example #1
0
    def __init__(self, option,
            grid=None,
            spot_max=1500.0,
            nspots=100,
            spotdensity=7.0,
            force_exact=True,
            flip_idx_spot=False,
            schemes={},
            cache=True,
            coefficients=None,
            boundaries=None,
            force_bandwidth=False,
            logspace=False,
            verbose=True
            ):
        """@option@ is a BlackScholesOption"""
        self.cache = cache
        assert isinstance(option, Option)

        self.option = option

        if logspace:
            def mu_s(t, *dim):     return option.interest_rate.value - 0.5*option.variance.value
            def gamma2_s(t, *dim): return 0.5 * option.variance.value
        else:
            def mu_s(t, *dim):     return option.interest_rate.value * dim[0]
            def gamma2_s(t, *dim): return 0.5 * option.variance.value * dim[0]**2


        if grid:
            self.grid = grid
            spots = self.grid.mesh[0]
        else:
            if logspace:
                dx = (np.log(spot_max) - np.log(option.spot)) / (nspots//2)
                spots = np.log(option.spot) + dx*np.linspace(-(nspots//2), nspots//2, nspots)
                init = lambda x: np.maximum(np.exp(x) - option.strike, 0)
                self.spots = np.exp(spots)
            else:
                spots = utils.sinh_space(option.spot, spot_max, spotdensity,
                        nspots, force_exact=force_exact)
                self.spots = spots
                init = lambda x: np.maximum(x - option.strike, 0)
            grid = Grid([spots], initializer=init)

        # spot = self.spots[self.idx]

        # self.option = BlackScholesOption(spot=np.exp(spot), strike=k, interest_rate=r,
                                     # variance=v, tenor=t)
        # G = Grid([spots], initializer=lambda *x: np.maximum(np.exp(x[0])-option.strike,0))


        if not coefficients:
            coefficients = {()   : lambda t: -option.interest_rate.value,
                    (0,) : mu_s,
                    (0,0): gamma2_s}

        if not boundaries:
            if logspace:
                boundaries = {       # D: U = 0              Von Neumann: dU/dS = 1
                        (0,)  : ((0, lambda *args: 0.0), (1, lambda t, x: np.exp(x))),
                                    # D: U = 0              Free boundary
                        (0,0)  : ((0, lambda *args: 0.0), (None, lambda t, x: np.exp(x)))}
            else:
                boundaries = {        # D: U = 0              Von Neumann: dU/dS = 1
                        (0,)  : ((0, lambda *args: 0.0), (1, lambda t, x: 1.0)),
                                    # D: U = 0              Free boundary
                        (0,0) : ((0, lambda *args: 0.0), (None, lambda t, x: 1.0))}


        FDE.FiniteDifferenceEngineADI.__init__(self,
                grid,
                coefficients=coefficients,
                boundaries=boundaries,
                schemes=schemes,
                force_bandwidth=force_bandwidth)
rho = 0


# Grid parameters
rate_Spot_Var = 0.5  # Proportion to solve in the var step

spot_max = 1500.0
var_max = 13.0

nspots = 100
nvols = 100

spotdensity = 7.0  # infinity is linear?
varexp = 4

spots = utils.sinh_space(k, spot_max, spotdensity, nspots)
spot = spots[min(abs(spots - spot)) == abs(spots - spot)][0]
k = spots[min(abs(spots - k)) == abs(spots - k)][0]
vars = utils.exponential_space(0.00, v0, var_max, varexp, nvols)
# vars = [v0]
# spots = linspace(0.0, spot_max, nspots)
# vars = linspace(0.0, var_max, nvols)
# plot(spots); title("Spots"); show()
# plot(vars); title("Vars"); show()

trims = (k * .2 < spots) & (spots < k * 2.0)
trimv = (0.01 < vars) & (vars < 1)  # v0*2.0)
trims = slice(None)
trimv = slice(None)

# Does better without upwinding here
Example #3
0
                 , mean_reversion = 1
                 , mean_variance = 0.04
                 , vol_of_variance = 0.4
                 , correlation = 0.3
                 )

spot_max = 1500.0
var_max = 13.0

nspots = 100
nvols = 100

spotdensity = 7.0  # infinity is linear?
varexp = 4

spots = utils.sinh_space(H.strike, spot_max, spotdensity, nspots)
vars = utils.exponential_space(0.00, H.variance.value, var_max, varexp, nvols)
# vars = [v0]
# spots = np.linspace(0.0, spot_max, nspots)
# vars = np.linspace(0.0, var_max, nvols)
# plot(spots); title("Spots"); show()
# plot(vars); title("Vars"); show()

H.strike = spots[min(abs(spots - H.strike)) == abs(spots - H.strike)][0]
H.spot = spots[min(abs(spots - H.spot)) == abs(spots - H.spot)][0]
def init(spots, vars):
    return np.maximum(0, spots - H.strike)
Gi = Grid(mesh=(spots, vars), initializer=init)
G = Gi.copy()
V_init = G.domain.copy()
Example #4
0
    def __init__(self,
                 option,
                 grid=None,
                 spot_max=1500.0,
                 nspots=100,
                 spotdensity=7.0,
                 force_exact=True,
                 flip_idx_spot=False,
                 schemes={},
                 cache=True,
                 coefficients=None,
                 boundaries=None,
                 force_bandwidth=False,
                 logspace=False,
                 verbose=True):
        """@option@ is a BlackScholesOption"""
        self.cache = cache
        assert isinstance(option, Option)

        self.option = option

        if logspace:

            def mu_s(t, *dim):
                return option.interest_rate.value - 0.5 * option.variance.value

            def gamma2_s(t, *dim):
                return 0.5 * option.variance.value
        else:

            def mu_s(t, *dim):
                return option.interest_rate.value * dim[0]

            def gamma2_s(t, *dim):
                return 0.5 * option.variance.value * dim[0]**2

        if grid:
            self.grid = grid
            spots = self.grid.mesh[0]
        else:
            if logspace:
                dx = (np.log(spot_max) - np.log(option.spot)) / (nspots // 2)
                spots = np.log(option.spot) + dx * np.linspace(
                    -(nspots // 2), nspots // 2, nspots)
                init = lambda x: np.maximum(np.exp(x) - option.strike, 0)
                self.spots = np.exp(spots)
            else:
                spots = utils.sinh_space(option.spot,
                                         spot_max,
                                         spotdensity,
                                         nspots,
                                         force_exact=force_exact)
                self.spots = spots
                init = lambda x: np.maximum(x - option.strike, 0)
            grid = Grid([spots], initializer=init)

        # spot = self.spots[self.idx]

        # self.option = BlackScholesOption(spot=np.exp(spot), strike=k, interest_rate=r,
        # variance=v, tenor=t)
        # G = Grid([spots], initializer=lambda *x: np.maximum(np.exp(x[0])-option.strike,0))

        if not coefficients:
            coefficients = {
                (): lambda t: -option.interest_rate.value,
                (0, ): mu_s,
                (0, 0): gamma2_s
            }

        if not boundaries:
            if logspace:
                boundaries = {  # D: U = 0              Von Neumann: dU/dS = 1
                    (0, ):
                    ((0, lambda *args: 0.0), (1, lambda t, x: np.exp(x))),
                    # D: U = 0              Free boundary
                    (0, 0):
                    ((0, lambda *args: 0.0), (None, lambda t, x: np.exp(x)))
                }
            else:
                boundaries = {  # D: U = 0              Von Neumann: dU/dS = 1
                    (0, ): ((0, lambda *args: 0.0), (1, lambda t, x: 1.0)),
                    # D: U = 0              Free boundary
                    (0, 0): ((0, lambda *args: 0.0), (None, lambda t, x: 1.0))
                }

        FDE.FiniteDifferenceEngineADI.__init__(self,
                                               grid,
                                               coefficients=coefficients,
                                               boundaries=boundaries,
                                               schemes=schemes,
                                               force_bandwidth=force_bandwidth)
Example #5
0
    def __init__(self, option,
            grid=None,
            spot_max=1500.0,
            spot_min=0.0,
            spots=None,
            vars=None,
            var_max=10.0,
            nspots=100,
            nvols=100,
            spotdensity=7.0,
            varexp=4.0,
            force_exact=True,
            flip_idx_var=False,
            flip_idx_spot=False,
            schemes=None,
            coefficients=None,
            boundaries=None,
            cache=True,
            verbose=True,
            force_bandwidth=None
            ):
        """@option@ is a HestonOption"""
        self.cache = cache
        assert isinstance(option, Option)
        self.option = option

        if not coefficients:
            def mu_s(t, *dim):
                # return option.interest_rate.value - 0.5 * dim[1]
                return option.interest_rate.value * dim[0]
            def gamma2_s(t, *dim):
                # return 0.5 * dim[1]
                return 0.5 * dim[1] * dim[0]**2
            def mu_v(t, *dim):
                if np.isscalar(dim[0]):
                    if dim[0] == 0:
                        return 0
                ret = option.variance.reversion * (option.variance.mean - dim[1])
                ret[dim[0]==0] = 0
                return ret
            def gamma2_v(t, *dim):
                if np.isscalar(dim[0]):
                    if dim[0] == 0:
                        return 0
                ret = 0.5 * option.variance.volatility**2 * dim[1]
                ret[dim[0]==0] = 0
                return ret
            def cross(t, *dim):
                # return option.correlation * option.variance.volatility * dim[1]
                return option.correlation * option.variance.volatility * dim[0] * dim[1]

            coefficients = {()   : lambda t: -option.interest_rate.value,
                    (0,) : mu_s,
                    (0,0): gamma2_s,
                    (1,) : mu_v,
                    (1,1): gamma2_v,
                    (0,1): cross,
                    }

        if not boundaries:
            boundaries = {
                            # D: U = 0              VN: dU/dS = 1
                    # (0,)  : ((0, lambda t, *dim: 0.0), (1, lambda t, *dim: np.exp(dim[0]))),
                    (0,)  : ((0, lambda t, *dim: 0.0), (1, lambda t, *dim: 1.0)),
                            # D: U = 0              Free boundary
                    # (0,0) : ((0, lambda t, *dim: 0.0), (None, lambda t, *dim:  np.exp(dim[0]))),
                    (0,0) : ((0, lambda t, *dim: 0.0), (None, lambda t, *dim: 1.0)),
                            # Free boundary at low variance
                    (1,)  : ((None, lambda t, *dim: None),
                            # # D intrinsic value at high variance
                            # (0, lambda t, *dim: np.exp(-option.interest_rate.value * t) * dim[0])
                            (None, lambda t, *dim: None)
                            # (0, lambda t, *dim: dim[0])
                            ),
                            # We know from the PDE that this will be 0 because
                            # the vol is 0 at the low boundary
                    (1,1) : ((1, lambda t, *dim: 0),
                            # D intrinsic value at high variance
                            # (0, lambda t, *dim: np.exp(-option.interest_rate.value * t) * np.maximum(0.0, np.exp(dim[0])-option.strike))),
                            (None, lambda t, *dim: None)
                            # (0, lambda t, *dim: dim[0])
                            # (0, lambda t, *dim: 0)
                            )
                    }

        if isinstance(option, BarrierOption):
            if option.top:
                if option.top[0]: # Knockin, not sure about implementing this
                    raise NotImplementedError("Knockin barriers are not supported.")
                else:
                    spot_max = option.top[1]
                    if grid:
                        assert np.allclose(spot_max, max(grid.mesh[0]))
                    boundaries[(0,)] = (boundaries[(0,)][0], (0, lambda *x: 0.0))
                    boundaries[(0,0)] = boundaries[(0,)]
            if option.bottom:
                if option.bottom[0]: # Knockin, not sure about implementing this
                    raise NotImplementedError("Knockin barriers are not supported.")
                else:
                    spot_min = option.bottom[1]
                    boundaries[(0,)] = ((0, lambda *x: 0.0), boundaries[(0,)][1])
                    boundaries[(0,0)] = boundaries[(0,)]


        if grid:
            self.spots = grid.mesh[0]
            self.vars = grid.mesh[1]
        else:
            if vars is None:
                # vars = np.linspace(0, var_max, nvols)
                vars = utils.exponential_space(0.00, option.variance.value, var_max,
                                            varexp, nvols,
                                            force_exact=force_exact)
            self.vars = vars
            if spots is None:
                # spots = np.linspace(0,spot_max,nspots)
                if isinstance(option, BarrierOption) and option.top and not option.top[0]:
                        p = 3
                        # spots = np.linspace(0, spot_max**p, nspots)**(1.0/p)
                        spots = utils.exponential_space(0.00, self.option.strike, spot_max,
                                                    1.0/p, nspots,
                                                    force_exact=force_exact)
                        print "Barrier spots"
                else:
                    spots = utils.sinh_space(option.strike-spot_min, spot_max-spot_min, spotdensity, nspots, force_exact=force_exact) + spot_min
            self.spots = spots
            grid = Grid([self.spots, self.vars], initializer=lambda *x: np.maximum(x[0]-option.strike,0))


        newstrike = self.spots[np.argmin(np.abs(self.spots - option.strike))]
        self.spots[np.argmin(np.abs(self.spots - option.spot))] = option.spot
        # if newstrike != option.strike:
            # print "Strike %s -> %s" % (option.strike, newstrike)
            # option.strike = newstrike
        # if newspot != option.spot:
            # print "Spot %s -> %s" % (option.spot, newspot)
            # option.spot = newspot

        if flip_idx_var is True: # Need explicit boolean True
            flip_idx_var = bisect_left(
                    np.round(self.vars, decimals=5),
                    np.round(option.variance.mean, decimals=5))
        if flip_idx_spot is True: # Need explicit boolean True
            flip_idx_spot = bisect_left(
                    np.round(self.spots, decimals=5),
                    np.round(option.strike, decimals=5))


        if schemes is None:
            schemes = {}
        else:
            schemes = {k : list(v) for k, v in schemes.items()}
            # for k,v in new.items():
                # assert schemes[k] is not v
            # schemes = new
        if (0,) not in schemes:
            schemes[(0,)] = [{"scheme": "center"}]
        if flip_idx_spot is not False:
            schemes[(0,)].append({"scheme": 'forward', "from" : flip_idx_spot})

        if (1,) not in schemes:
            schemes[(1,)] = [{"scheme": "center"}]
        if flip_idx_var is not False:
            schemes[(1,)].append({"scheme": 'backward', "from" : flip_idx_var})

        if verbose:
            print "(0,): Start with %s differencing." % (schemes[(0,)][0]['scheme'],)
            if len(schemes[(0,)]) > 1:
                print "(0,): Switch to %s differencing at %i." % (schemes[(0,)][1]['scheme'], schemes[(0,)][1]['from'])
            print "(1,): Start with %s differencing." % (schemes[(1,)][0]['scheme'],)
            if len(schemes[(1,)]) > 1:
                print "(1,): Switch to %s differencing at %i." % (schemes[(1,)][1]['scheme'], schemes[(1,)][1]['from'])


        self.grid = grid
        self.coefficients = coefficients
        self.boundaries = boundaries
        self.schemes = schemes
        self.force_bandwidth = force_bandwidth
        self._initialized = False
Example #6
0
sigma = 0.4
rho = 0

# Grid parameters
rate_Spot_Var = 0.5  # Proportion to solve in the var step

spot_max = 1500.0
var_max = 13.0

nspots = 100
nvols = 100

spotdensity = 7.0  # infinity is linear?
varexp = 4

spots = utils.sinh_space(k, spot_max, spotdensity, nspots)
spot = spots[min(abs(spots - spot)) == abs(spots - spot)][0]
k = spots[min(abs(spots - k)) == abs(spots - k)][0]
vars = utils.exponential_space(0.00, v0, var_max, varexp, nvols)
# vars = [v0]
# spots = linspace(0.0, spot_max, nspots)
# vars = linspace(0.0, var_max, nvols)
# plot(spots); title("Spots"); show()
# plot(vars); title("Vars"); show()

trims = (k * .2 < spots) & (spots < k * 2.0)
trimv = (0.01 < vars) & (vars < 1)  # v0*2.0)
trims = slice(None)
trimv = slice(None)

# Does better without upwinding here