from Constantes import *

def payoff(x, K):
    #Put
    return np.maximum(K - x, 0)
    
    #Call
    #return np.maximum(x - K, 0)

def Prix_en_zero_rec(N,K,r,a,b,x):
  # Prix du put dans le Modele CRR
  # Noter que ce prix ne depend pas de p
  
  # on commence par calculer la "proba" p* qui permet d'evaluer  le prix par replication
    p_etoile = (b - r) / (b - a) # proba d'aller en 1+a
    p1 = p_etoile / (1 + r)# proba "actualisee" de choisir 1+a
    p2 = (1 - p_etoile) / (1 + r) # proba "actualisee" de choisir 1+b
  
    return Prix_rec(0,N,K,p1,p2,a,b,x)

def Prix_rec(n,N,K,p1,p2,a,b,x):
# Version recursive pour verifier
# Prix du put dans le Modele CRR
    if n == N :
        return payoff(x,K)
    
    return ????????

# Une version iterative (beaucoup) plus efficace mais moins facile a comprendre
def Prix_en_zero(N,K,r,a,b,x):
    p_etoile = (b - r) / (b - a) # proba d'aller en 1+a
    p1 = p_etoile / (1 + r) # proba de choisir 1+a
    p2 = (1 - p_etoile) / (1 + r) # proba de choisir 1+b
    # xi(i) = x(1+a)^(N-i) (1+b)^i
    xi=np.zeros(N+1);
    xi[0] = x * (1+a)**N
    ro = (1+b) / (1+a)
    for i in range(1,N+1):
        xi[i] = ro * xi[i-1]
        
    # en N : P[i+1] = (x(1+a)^(N-i) (1+b)^i-K)+ 
    #P=np.zeros(N+1)
    #for i in range(N):     
    #    P[i] = payoff(xi[i],K)
    P = payoff(xi, K)
    
    # A un instant j, 
    #     P[i+1] approxime P(j,x(1+a)^(N-j-i) (1+b)^i) i=0,...,N-j
    #       i      nbre de choix "up" (1+b) entre j+1 et N
    #       N-j-i  nbre de choix "down" (1+a) entre j+1 et N
    for j in range(N+1):
        for i in range(N - j ):
            P[i] =  p1 * P[i] + p2 * P[i + 1]        
    return P[0]


#Prix par une méthode Monte Carlo

def SN(M,N,p,a,b,S0):
    V = np.random.rand(M,N) > p
    W = np.concatenate((np.zeros(M).reshape(-1,1),np.cumsum(math.log(1+a) + math.log((1+b)/(1+a))*V, axis = 1)), axis = 1)
    Z = S0*np.exp(W)
    
    return Z[:,-1]


def Prix_MC_en_zero(M,N,K,r,a,b,S0):
    #A COMPLETER
    p=?????
    cours=SN(M,N,p,a,b,S0)
    #A COMPLETER
    payoffActualise=?????? 
    prix=np.mean(payoffActualise)
    
    prixInf=prix-1.96*np.std(payoffActualise)/math.sqrt(M);
    prixSup=prix+1.96*np.std(payoffActualise)/math.sqrt(M);
    return prixInf, prixSup


print('Prix_en_zero_rec : ', Prix_en_zero_rec(N,K,r,a,b,S0))
print('Prix_en_zero : ', Prix_en_zero(N,K,r,a,b,S0))
print('Prix_MC_en_zero : ', Prix_MC_en_zero(200000,N,K,r,a,b,S0))
