/-
Copyright (c) 2026 Raphael Coelho. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Raphael Coelho
-/
module

public import Mathlib
public import MathFin.Binomial.CRRCharFun
public import MathFin.BlackScholes.Put

/-!
# CRR → Black–Scholes call price, in closed form

`binomialPrice_call_tendsto_bs` lands the binomial call-price limit in the
put-call-parity *integral* form `e^{−rT}·E[(K − S_T)₊] + (S₀ − K e^{−rT})`.
This file chains it to the literal Black–Scholes closed form
`S₀·Φ(d₁) − K·e^{−rT}·Φ(d₂)`, via the BS put formula (`bs_put_formula`,
instantiated on the terminal law `N((r−σ²/2)T, σ²T)` through the standardisation
`Z = (· − (r−σ²/2)T)/(σ√T)`) and the CDF symmetry `Φ(−x) = 1 − Φ(x)`.
-/

@[expose] public section

namespace MathFin

open MeasureTheory ProbabilityTheory Real Filter
open scoped NNReal ENNReal Topology

/-- The discounted put expectation over the BS terminal law `N((r−σ²/2)T, σ²T)`
equals the Black–Scholes put price `K e^{−rT} Φ(−d₂) − S₀ Φ(−d₁)`. Proved by
instantiating `bs_put_formula` on that gaussian with the standardisation
`Z = (· − (r−σ²/2)T)/(σ√T)` (which has `N(0,1)` law), under which the BS
terminal `bsTerminal S₀ r σ T (Z x)` collapses to `S₀·eˣ`. -/
lemma exp_neg_mul_integral_put_gaussian_eq {r σ T S₀ K : ℝ}
    (hσ : 0 < σ) (hT : 0 < T) (hS₀ : 0 < S₀) (hK : 0 < K) :
    Real.exp (-(r * T)) * ∫ x, max (K - S₀ * Real.exp x) 0
        ∂(gaussianReal ((r - σ ^ 2 / 2) * T) (σ ^ 2 * T).toNNReal)
      = K * Real.exp (-(r * T)) * Phi (-(bsd2 S₀ K r σ T))
        - S₀ * Phi (-(bsd1 S₀ K r σ T)) := by
  set μ_bs : ℝ := (r - σ ^ 2 / 2) * T with hμ
  set ν : ℝ := σ * Real.sqrt T with hν
  have hν_pos : 0 < ν := mul_pos hσ (Real.sqrt_pos.mpr hT)
  have hσ2T_pos : 0 < σ ^ 2 * T := by positivity
  -- Standardisation `Z = (· − μ_bs)/ν` has `N(0,1)` law under the BS gaussian.
  have hlaw : HasLaw (fun x => (x - μ_bs) / ν) (gaussianReal 0 1)
      (gaussianReal μ_bs (σ ^ 2 * T).toNNReal) := by
    have h1 := gaussianReal_sub_const
      (HasLaw.id (μ := gaussianReal μ_bs (σ ^ 2 * T).toNNReal)) μ_bs
    have h2 := gaussianReal_div_const h1 ν
    have hmk : NNReal.mk (ν ^ 2) (sq_nonneg _) = (σ ^ 2 * T).toNNReal := by
      apply NNReal.eq
      simp only [NNReal.coe_mk]
      rw [hν, mul_pow, Real.sq_sqrt hT.le]
      exact (Real.coe_toNNReal _ hσ2T_pos.le).symm
    have hvar : ((σ ^ 2 * T).toNNReal / NNReal.mk (ν ^ 2) (sq_nonneg _)) = 1 := by
      rw [hmk]; exact div_self (Real.toNNReal_pos.mpr hσ2T_pos).ne'
    simp only [id_eq] at h2
    convert h2 using 2
    · rw [sub_self, zero_div]
    · rw [hvar]
  have hbs : BSCallHyp (gaussianReal μ_bs (σ ^ 2 * T).toNNReal) S₀ K r σ T
      (fun x => (x - μ_bs) / ν) := ⟨hS₀, hK, hσ, hT, hlaw⟩
  have hpf := bs_put_formula hbs
  -- `bsTerminal S₀ r σ T ((x − μ_bs)/ν) = S₀ · eˣ`.
  have hterm : (fun x : ℝ => Real.exp (-r * T) *
        max (K - bsTerminal S₀ r σ T ((x - μ_bs) / ν)) 0)
      = (fun x : ℝ => Real.exp (-r * T) * max (K - S₀ * Real.exp x) 0) := by
    funext x
    have hb : bsTerminal S₀ r σ T ((x - μ_bs) / ν) = S₀ * Real.exp x := by
      rw [bsTerminal]
      congr 2
      rw [hμ, hν]
      field_simp
      ring
    rw [hb]
  rw [hterm] at hpf
  rw [← integral_const_mul, show Real.exp (-(r * T)) = Real.exp (-r * T) from by
    rw [neg_mul]]
  exact hpf

/-- **Cox–Ross–Rubinstein → Black–Scholes, closed form.** Under no-arbitrage at
every step, the `n`-step CRR binomial call price converges to the *literal*
Black–Scholes call price `S₀·Φ(d₁) − K·e^{−rT}·Φ(d₂)`.

This is `binomialPrice_call_tendsto_bs` with its put-call-parity integral limit
chained, via `exp_neg_mul_integral_put_gaussian_eq` + `Phi_neg`, onto the closed
`Φ`-form. -/
theorem binomialPrice_call_tendsto_bs_closed {r σ T S₀ K : ℝ}
    (hσ : 0 < σ) (hT : 0 < T) (hS₀ : 0 < S₀) (hK : 0 < K)
    (hna : ∀ n, BinomialNoArb (crrUp σ T n) (crrDown σ T n) (crrPerStepRate r T n)) :
    Tendsto (fun n : ℕ => binomialPrice (crrUp σ T n) (crrDown σ T n) (crrPerStepRate r T n)
        (fun x => max (x - K) 0) n S₀) atTop
      (𝓝 (S₀ * Phi (bsd1 S₀ K r σ T)
          - K * Real.exp (-(r * T)) * Phi (bsd2 S₀ K r σ T))) := by
  have h := binomialPrice_call_tendsto_bs (K := K) hσ hT hS₀ hna
  have hkey : Real.exp (-(r * T)) * ∫ x, max (K - S₀ * Real.exp x) 0
        ∂(gaussianReal ((r - σ ^ 2 / 2) * T) (σ ^ 2 * T).toNNReal)
      + (S₀ - K * Real.exp (-(r * T)))
      = S₀ * Phi (bsd1 S₀ K r σ T)
        - K * Real.exp (-(r * T)) * Phi (bsd2 S₀ K r σ T) := by
    rw [exp_neg_mul_integral_put_gaussian_eq hσ hT hS₀ hK,
        Phi_neg (bsd2 S₀ K r σ T), Phi_neg (bsd1 S₀ K r σ T)]
    ring
  rwa [hkey] at h

end MathFin
