import numpy as np  
import scipy.stats as ss  
  
  
#base  
class OptionGreek:  
    price = 0  
    delta = 0  
    gamma = 0  
    theta = 0  
    def __init__(self):  
        pass  
  
class OptionContract(object):  
    _K = 0.0  
    _Sigma = 0.0  
    def __init__(self, k, sigma):  
        self._K = float(k)  
        self._Sigma = float(sigma)  
  
    def printSelf(self):  
        print "sigma\tVolatility:", self._Sigma  
        print "K\tStrike:", self._K  
          
      
#vanilla european options  
class OptionContractCall(OptionContract):  
    def expiC(self, S ):  
        return np.maximum(S-self._K, 0.0)  
    def d1(self, S0, K, r, sigma, T):  
        return (np.log(S0 / K) + (r + sigma**2 / 2) * T) / (sigma * np.sqrt(T))  
    def d2(self, S0, K, r, sigma, T):  
        return (np.log(S0 / K) + (r - sigma**2 / 2) * T) / (sigma * np.sqrt(T))  
    def expiCR(self, S0, r =0, sigma =0, T =1):  
        return S0*ss.norm.cdf(self.d1(S0, self._K, r, sigma, T)) - self._K * np.exp(-r * T) * ss.norm.cdf(self.d2(S0, self._K, r, sigma, T))          
     
    call=OptionGreek()  
      
    def printSelf(self):  
        super(OptionContractCall, self).printSelf()  
        print "call price:", self.call.price  
      
    def __init__(self, K, sigma):  
        self.call=OptionGreek()  
        super(OptionContractCall, self).__init__(K, sigma)  
  
  
  
class OptionContractPut(OptionContract):  
    def expiP(self, S):  
        return np.maximum(-S+self._K, 0.0)  
    def d1(self, S0, K, r, sigma, T):  
        return (np.log(S0 / K) + (r + sigma**2 / 2) * T) / (sigma * np.sqrt(T))  
    def d2(self, S0, K, r, sigma, T):  
        return (np.log(S0 / K) + (r - sigma**2 / 2) * T) / (sigma * np.sqrt(T))  
    def expiPR(self, S0, r=0, sigma=0, T=1):  
        return self._K * np.exp(-r * T) * ss.norm.cdf(-self.d2(S0, self._K, r, sigma, T)) - S0 * ss.norm.cdf(-self.d1(S0, self._K, r, sigma, T))  
          
    def printSelf(self):  
        super(OptionContractPut, self).printSelf()  
        print "put price:", self.put.price  
  
    put=OptionGreek()  
     
    def __init__(self, K, sigma):  
        self.put=OptionGreek()  
        super(OptionContractPut, self).__init__(K, sigma)  
  
  
class OptionContractDuo(OptionContractPut, OptionContractCall):  
    def printSelf(self):  
        super(OptionContractDuo, self).printSelf()  
  
    def __init__(self, K, sigma):  
        super(OptionContractDuo, self).__init__(K, sigma)  