Cash or Nothing COS Method¶
Background¶
Cos Method Cash Or Nothing
Educational script demonstrating cos method cash or nothing concepts.
Code¶
```python """ Cos Method Cash Or Nothing
Educational script demonstrating cos method cash or nothing concepts. """
@title Cash or Nothing COS Method¶
Source Code¶
https://github.com/LechGrzelak/Computational-Finance-Course/blob/main/¶
Lecture%2008-%20Fourier%20Transformation%20for%20Option%20Pricing/Materials/¶
CashOrNothing_COS_Method.py¶
import numpy as np import matplotlib.pyplot as plt import scipy.stats as st import time
======================================================================¶
def CashOrNothingPriceCOSMthd(cf,CP,S0,r,tau,K,N,L): # cf - characteristic function as a functon, in the book denoted as \varphi # CP - C for call and P for put # S0 - Initial stock price # r - interest rate (constant) # tau - time to maturity # K - list of strikes # N - Number of expansion terms # L - size of truncation domain (typ.:L=8 or L=10)
# reshape K to a column vector
K = np.array(K).reshape([len(K),1])
#assigning i=sqrt(-1)
i = np.complex(0.0,1.0)
x0 = np.log(S0 / K)
# truncation domain
a = 0.0 - L * np.sqrt(tau)
b = 0.0 + L * np.sqrt(tau)
# sumation from k = 0 to k=N-1
k = np.linspace(0,N-1,N).reshape([N,1])
u = k * np.pi / (b - a);
# Determine coefficients for Put Prices
H_k = CashOrNothingCoefficients(CP,a,b,k)#CallPutCoefficients(CP,a,b,k)
mat = np.exp(i * np.outer((x0 - a) , u))
temp = cf(u) * H_k
temp[0] = 0.5 * temp[0]
value = np.exp(-r * tau) *K * np.real(mat.dot(temp))
return value
""" Determine coefficients for CashOrNothing """ def CashOrNothingCoefficients(CP,a,b,k): if str(CP).lower()=="c" or str(CP).lower()=="1": c = 0.0 d = b coef = Chi_Psi(a,b,c,d,k) Psi_k = coef["psi"] if a < b and b < 0.0: H_k = np.zeros([len(k),1]) else: H_k = 2.0 / (b - a) * (Psi_k)
elif str(CP).lower()=="p" or str(CP).lower()=="-1":
c = a
d = 0.0
coef = Chi_Psi(a,b,c,d,k)
Psi_k = coef["psi"]
H_k = 2.0 / (b - a) * (Psi_k)
return H_k
def Chi_Psi(a,b,c,d,k): psi = np.sin(k * np.pi * (d - a) / (b - a)) - np.sin(k * np.pi * (c - a)/(b - a)) psi[1:] = psi[1:] * (b - a) / (k[1:] * np.pi) psi[0] = d - c
chi = 1.0 / (1.0 + np.power((k * np.pi / (b - a)) , 2.0))
expr1 = np.cos(k * np.pi * (d - a)/(b - a)) * np.exp(d) - np.cos(k * np.pi
* (c - a) / (b - a)) * np.exp(c)
expr2 = k * np.pi / (b - a) * np.sin(k * np.pi *
(d - a) / (b - a)) - k * np.pi / (b - a) * np.sin(k
* np.pi * (c - a) / (b - a)) * np.exp(c)
chi = chi * (expr1 + expr2)
value = {"chi":chi,"psi":psi }
return value
def BS_Cash_Or_Nothing_Price(CP,S_0,K,sigma,tau,r): #Black-Scholes Call option price cp = str(CP).lower() K = np.array(K).reshape([len(K),1]) d1 = (np.log(S_0 / K) + (r + 0.5 * np.power(sigma,2.0)) * tau) / float(sigma * np.sqrt(tau)) d2 = d1 - sigma * np.sqrt(tau) if cp == "c" or cp == "1": value = K * np.exp(-r * tau) * st.norm.cdf(d2) elif cp == "p" or cp =="-1": value = K * np.exp(-r * tau) *(1.0 - st.norm.cdf(d2)) return value
def main(): i = np.complex(0.0,1.0)
CP = "p"
S0 = 100.0
r = 0.05
tau = 0.1
sigma = 0.2
K = [120] #np.linspace(10,S0*2.0,50)#[120.0]#
N = [40, 60, 80, 100, 120, 140]
L = 6
# Definition of the characteristic function for the GBM, this is an input
# for the COS method
# Note that Chf does not include coefficient "+iuX(t_0)" this coefficient
# is included internally in the evaluation
# In the book we denote this function as \varphi(u)
cf = lambda u: np.exp((r - 0.5 * np.power(sigma,2.0)) * i * u * tau - 0.5
* np.power(sigma, 2.0) * np.power(u, 2.0) * tau)
val_COS_Exact = CashOrNothingPriceCOSMthd(cf,CP,S0,r,tau,K,np.power(2,14),L);
print("Reference value is equal to ={0}".format(val_COS_Exact[0][0]))
# Timing results
NoOfIterations = 1000
for n in N:
time_start = time.time()
for k in range(0,NoOfIterations):
val_COS = CashOrNothingPriceCOSMthd(cf,CP,S0,r,tau,K,n,L)[0]
print("For N={0} the error is ={1}".format(n,val_COS[0]-val_COS_Exact[0]))
time_stop = time.time()
print("It took {0} seconds to price.".format((time_stop-time_start)/float(NoOfIterations)))
if name == "main": main() ```
Exercises¶
Exercise 1. A cash-or-nothing call pays \(K\) if \(S_T > K\) and zero otherwise. Write its discounted payoff and the Black-Scholes closed-form price.
Solution to Exercise 1
Discounted payoff: \(Ke^{-rT}\mathbf{1}_{S_T > K}\). The BS price is \(V = Ke^{-rT}N(d_2)\) where \(d_2 = \frac{\ln(S_0/K) + (r - \sigma^2/2)T}{\sigma\sqrt{T}}\). This differs from a standard call because there is no \((S_T - K)\) factor---the payoff is a fixed amount \(K\) conditional on finishing ITM.
Exercise 2. In the COS method, the cash-or-nothing coefficients use only \(\Psi_k\) (not \(\text{Chi}_k\)). Explain why the exponential coefficient is absent.
Solution to Exercise 2
The cash-or-nothing payoff is \(K \cdot \mathbf{1}_{x > 0}\) (in log-space), which does not contain the \(e^x\) factor present in vanilla options. The Fourier-cosine expansion of this indicator function involves only \(\Psi_k = \int \cos(k\pi(x-a)/(b-a))dx\) over the ITM region, without the exponential weighting. The Chi coefficients, which capture \(\int e^x \cos(\cdot)dx\), are needed only for payoffs proportional to \(S_T\).
Exercise 3. The cash-or-nothing put pays \(K\) if \(S_T < K\). Using put-call parity for digitals, express its price in terms of the cash-or-nothing call price.
Solution to Exercise 3
Since the events \(\{S_T > K\}\) and \(\{S_T < K\}\) are complementary (ignoring the zero-probability event \(S_T = K\)): \(V_{\text{put}} + V_{\text{call}} = Ke^{-rT}\). Therefore \(V_{\text{put}} = Ke^{-rT} - V_{\text{call}} = Ke^{-rT}(1 - N(d_2)) = Ke^{-rT}N(-d_2)\).
Exercise 4. For \(N = 40\) COS terms, the cash-or-nothing error is larger than for vanilla options with the same \(N\). Explain why discontinuous payoffs require more terms.
Solution to Exercise 4
The cash-or-nothing payoff has a discontinuity at \(S = K\) (jump from 0 to \(K\)). The Fourier cosine series converges slowly for discontinuous functions (Gibbs phenomenon), with error \(O(1/N)\) rather than the exponential convergence seen for smooth payoffs. The vanilla payoff has a kink (continuous but not differentiable), giving \(O(1/N^2)\) convergence. For \(N = 40\), the digital error can be \(\sim 2.5\%\) versus \(< 0.01\%\) for vanilla options.