// Bisection Algorithm for Black Scholes Implied Volatility =================================================================================
        public double BisecBSIV(string PutCall, double S, double K, double rf, double q, double T, double a, double b, double MktPrice, double Tol, int MaxIter)
        {
            BlackScholesPrice BS       = new BlackScholesPrice();
            double            lowCdif  = MktPrice - BS.BlackScholes(S, K, T, rf, q, a, PutCall);
            double            highCdif = MktPrice - BS.BlackScholes(S, K, T, rf, q, b, PutCall);
            double            BSIV     = 0.0;
            double            midP;

            if (lowCdif * highCdif > 0.0)
            {
                BSIV = -1.0;
            }
            else
            {
                for (int x = 0; x <= MaxIter; x++)
                {
                    midP = (a + b) / 2.0;
                    double midCdif = MktPrice - BS.BlackScholes(S, K, T, rf, q, midP, PutCall);
                    if (Math.Abs(midCdif) < Tol)
                    {
                        break;
                    }
                    else
                    {
                        if (midCdif > 0.0)
                        {
                            a = midP;
                        }
                        else
                        {
                            b = midP;
                        }
                    }
                    BSIV = midP;
                }
            }
            return(BSIV);
        }
        public double VarianceSwap(double[] KCI, double[] CallVI, double[] KPI, double[] PutVI, double S, double T, double rf, double q)
        {
            // Demeterfi et al (1999) fair strike of a variance swap
            // INPUTS
            //   KCI = Grid of call strikes
            //   CallVI = Interpolated call implied vol along the grid KCI
            //   KPI  = Grid of put strikes
            //   PutVI  = Interpolated put implied vol along the grid KPI
            //   S = Spot price
            //   T = Maturity
            //   rf = interest rate
            //   q = dividend yield

            // Do the required calculations on calls.
            // Rename CallK and CallV for convenience.
            int n = CallVI.Length;

            // Take ATM as the boundary point
            double Sb = S;

            // Start the replication algorithm
            double[]          Temp        = new double[n - 1];
            double[]          CallWeight  = new double[n - 1];
            double[]          CallValue   = new double[n - 1];
            double[]          CallContrib = new double[n - 1];
            BlackScholesPrice BS          = new BlackScholesPrice();

            for (int k = 0; k <= n - 2; k++)
            {
                Temp[k] = (f(KCI[k + 1], Sb, T) - f(KCI[k], Sb, T)) / (KCI[k + 1] - KCI[k]);
                if (k == 0)
                {
                    CallWeight[0] = Temp[0];
                }
                CallValue[k] = BS.BlackScholes(S, KCI[k], T, rf, q, CallVI[k], "C");
                if (k > 0)
                {
                    CallWeight[k] = Temp[k] - Temp[k - 1];
                }
                CallContrib[k] = CallValue[k] * CallWeight[k];
            }
            double Pi1 = CallContrib.Sum();

            // Do the calculations on puts. Flip the Vectors for Convenience
            n = PutVI.Length;
            Array.Reverse(KPI);
            Array.Reverse(PutVI);
            double[] Temp2      = new double[n - 1];
            double[] PutWeight  = new double[n - 1];
            double[] PutValue   = new double[n - 1];
            double[] PutContrib = new double[n - 1];
            for (int k = 0; k <= n - 2; k++)
            {
                Temp2[k] = (f(KPI[k + 1], Sb, T) - f(KPI[k], Sb, T)) / (KPI[k] - KPI[k + 1]);
                if (k == 0)
                {
                    PutWeight[0] = Temp2[0];
                }
                PutValue[k] = BS.BlackScholes(S, KPI[k], T, rf, q, PutVI[k], "P");
                if (k > 0)
                {
                    PutWeight[k] = Temp2[k] - Temp2[k - 1];
                }
                PutContrib[k] = PutValue[k] * PutWeight[k];
            }
            double Pi2 = PutContrib.Sum();

            // Total cost of the portfolio
            double Pi_CP = Pi1 + Pi2;

            // Results of the replication
            // Estimate of fair variance
            double Kvar = 2.0 / T * (rf * T - (S / Sb * Math.Exp(rf * T) - 1.0) - Math.Log(Sb / S)) + Math.Exp(rf * T) * Pi_CP;

            return(Kvar);
        }