Overall Statistics
Total Trades
1
Average Win
0%
Average Loss
0%
Compounding Annual Return
19.268%
Drawdown
0.700%
Expectancy
0
Net Profit
0%
Sharpe Ratio
4.099
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0.176
Beta
-0.117
Annual Standard Deviation
0.031
Annual Variance
0.001
Information Ratio
-2.063
Tracking Error
0.134
Treynor Ratio
-1.098
Total Fees
$1.00
namespace QuantConnect {

    /// <summary>
    /// Black Scholes class to calculate the theoretical prices of European options (and Americans as an approximation)
	/// </summary>
    public static class BlackScholes
    {
    	private static double[] nsia = { 2.50662823884, -18.61500062529, 41.39119773534, -25.44106049637 };
        private static double[] nsib = { -8.4735109309, 23.08336743743, -21.06224101826, 3.13082909833 };
        private static double[] nsic = { 0.3374754822726147, 0.9761690190917186, 0.1607979714918209, 0.0276438810333863, 0.0038405729373609, 0.0003951896511919, 0.0000321767881768, 0.0000002888167364, 0.0000003960315187 };

        //cumulative normal distribution function
        private static double CND(double X)
        {
            double L = 0.0;
            double K = 0.0;
            double dCND = 0.0;
            const double a1 = 0.31938153;
            const double a2 = -0.356563782;
            const double a3 = 1.781477937;
            const double a4 = -1.821255978;
            const double a5 = 1.330274429;
            L = Math.Abs(X);
            K = 1.0 / (1.0 + 0.2316419 * L);
            dCND = 1.0 - 1.0 / Math.Sqrt(2 * Convert.ToDouble(Math.PI.ToString())) *
                Math.Exp(-L * L / 2.0) * (a1 * K + a2 * K * K + a3 * Math.Pow(K, 3.0) +
                a4 * Math.Pow(K, 4.0) + a5 * Math.Pow(K, 5.0));

            if (X < 0)
            {
                return 1.0 - dCND;
            }
            else
            {
                return dCND;
            }
        }

        //function phi
        private static double phi(double x)
        {
            double phi = 0.0;
            phi = Math.Exp(-x * x / 2) / Math.Sqrt(2 * Math.PI);
            return phi;
        }

        public static double NORMSINV(double probability)
        {
            double r = 0;
            double x = 0;
            x = probability - 0.5;
            if (Math.Abs(x) < 0.42)
            {
                r = x * x;
                r = x * (((nsia[3] * r + nsia[2]) * r + nsia[1]) * r + nsia[0]) / ((((nsib[3] * r + nsib[2]) * r + nsib[1]) * r + nsib[0]) * r + 1);
                return r;
            }
            r = probability;
            if (x > 0)
                r = 1 - probability;

            r = Math.Log(-Math.Log(r));
            r = nsic[0] + r * (nsic[1] + r * (nsic[2] + r * (nsic[3] + r * (nsic[4] + r * (nsic[5] + r * (nsic[6] + r * (nsic[7] + r * nsic[7])))))));
            return Math.Abs(r);
        }
        
        public static double NORMINV(double probability, double mean, double standard_deviation)
        {
            return (NORMSINV(probability) * standard_deviation + mean);
        }

        public static double NORMINV(double probability, double[] values)
        {
            return NORMINV(probability, Mean(values), StandardDeviation(values));
        }

        public static double Mean(double[] values)
        {
            double tot = 0;
            foreach (double val in values)
                tot += val;

            return (tot / values.Length);
        }
        
        public static double StandardDeviation(double[] values)
        {
            return Math.Sqrt(Variance(values));
        }
        
        public static double Variance(double[] values)
        {
            double m = Mean(values);
            double result = 0;
            foreach (double d in values)
                result += Math.Pow((d - m), 2);

            return (result / values.Length);
        }

		// calculate centered historical volatility over the last two weeks
		// derived from the annualized log difference of current price and last price
		public static double HistoricalVolatility(double[] historicalPrices) {
			double[] logDifferences = new double[historicalPrices.Length-1];
			for (int i = 1; i < historicalPrices.Length; i++) {
				logDifferences[i-1] = Math.Log(historicalPrices[i]/historicalPrices[i-1]);
			}
			double meanLogDifferences = Mean(logDifferences);
			double sumSquaredVariances = 0;
			for (int i = 0; i < logDifferences.Length; i++) {
				logDifferences[i] = Math.Pow(logDifferences[i] - meanLogDifferences,2);
				sumSquaredVariances += Math.Pow(logDifferences[i] - meanLogDifferences,2);
			}
			double sqrtAverageVariance = Math.Sqrt(sumSquaredVariances/logDifferences.Length);
			double annualizedVariance = sqrtAverageVariance*Math.Sqrt(252);
			
			return annualizedVariance;
		}


        //Call pricer
        public static double blsCall(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            double Call = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            Call = Price * Math.Exp(-Yield * Time) * CND(d1) - Strike * Math.Exp(-Rate * Time) * CND(d2);
            return Call;
        }

        //Put pricer
        public static double blsPut(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            double Put = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            Put = Strike * Math.Exp(-Rate * Time) * CND(-d2) - Price * Math.Exp(-Yield * Time) * CND(-d1);
            return Put;
        }

        //delta for Call
        public static double blsdeltaCall(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            return Math.Exp(-Yield * Time) * CND(d1);
        }

        //delta for Put
        public static double blsdeltaPut(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            return Math.Exp(-Yield * Time) * CND(d1) - 1;
        }

        //gamma is the same for Put and Call
        public static double blsgamma(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            return Math.Exp(-Yield * Time) * phi(d1) / (Price * Volatility * Math.Sqrt(Time));
        }

        //vega is the same for Put and Call
        public static double blsvega(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            return Price * Math.Exp(-Yield * Time) * phi(d1) * Math.Sqrt(Time);
        }

        //theta for Call
        public static double blsthetaCall(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            return -Math.Exp(-Yield * Time) *( Price * phi(d1) * Volatility / (2 * Math.Sqrt(Time))) - Rate * Strike * Math.Exp(-Rate * Time) * CND(d2) + Yield * Price * Math.Exp(-Yield * Time) * CND(d1);
        }

        //theta for Put
        public static double blsthetaPut(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            return -Math.Exp(-Yield * Time) *( Price * phi(d1) * Volatility / (2 * Math.Sqrt(Time))) + Rate * Strike * Math.Exp(-Rate * Time) * CND(-d2) - Yield * Price * Math.Exp(-Yield * Time) * CND(-d1);
        }

        //rho for Call
        public static double blsrhoCall(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            return Strike * Time * Math.Exp(-Rate * Time) * CND(d2);
        }

        //rho for Put
        public static double blsrhoPut(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            return -Strike * Time * Math.Exp(-Rate * Time) * CND(-d2);
        }

        //volga is the same for Call and Put
        public static double blsvolga(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            return Price * Math.Exp(-Yield * Time) * phi(d1) * Math.Sqrt(Time) * d1 * d2 / Volatility;

        }

        //vanna is the same for Call and Put
        public static double blsvanna(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            double vanna = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            vanna = -Math.Exp(-Yield * Time) * phi(d1) * d2 / Volatility;
            return vanna;
        }

        //charm for Call
        public static double blscharmCall(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            double charmC = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            charmC = -Yield * Math.Exp(-Yield * Time) * CND(d1) + Math.Exp(-Yield * Time) * phi(d1) * (2 * (Rate - Yield) * Time - d2 * Volatility * Math.Sqrt(Time)) / (2 * Time * Volatility * Math.Sqrt(Time));
            return charmC;
        }

        //charm for Put
        public static double blscharmPut(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            double charmP = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            charmP = Yield * Math.Exp(-Yield * Time) * CND(-d1) - Math.Exp(-Yield * Time) * phi(d1) * (2 * (Rate - Yield) * Time - d2 * Volatility * Math.Sqrt(Time)) / (2 * Time * Volatility * Math.Sqrt(Time));
            return charmP;
        }

        //color is the same for Call and Put
        public static double blscolor(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            double color = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            color = -Math.Exp(-Yield * Time) * (phi(d1) / (2 * Price * Time * Volatility * Math.Sqrt(Time))) * (2 * Yield * Time + 1 + (2 * (Rate - Yield) * Time - d2 * Volatility * Math.Sqrt(Time)) * d1 / (2 * Time * Volatility * Math.Sqrt(Time)));
            return color;
        }

        //dual delta for Call
        public static double blsdualdeltaCall(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            double ddelta = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            ddelta = -Math.Exp(-Rate * Time) * CND(d2);
            return ddelta;
        }

        //dual delta for Put
        public static double blsdualdeltaPut(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            double ddelta = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            ddelta = Math.Exp(-Rate * Time) * CND(-d2);
            return ddelta;
        }

        //dual gamma is the same for Call and Put
        public static double blsdualgamma(double Price, double Strike, double Rate, double Time, double Volatility, double Yield)
        {
            double d1 = 0.0;
            double d2 = 0.0;
            double dgamma = 0.0;
            d1 = (Math.Log(Price / Strike) + (Rate - Yield + Volatility * Volatility / 2.0) * Time) / (Volatility * Math.Sqrt(Time));
            d2 = d1 - Volatility * Math.Sqrt(Time);
            dgamma = Math.Exp(-Rate * Time) * phi(d2) / (Strike * Volatility * Math.Sqrt(Time));
            return dgamma;
        }
        
		/// <summary>
        /// Counts the number of week days (business days). Not so robust. Better to use real calendar.
		/// </summary>
        public static double CountWeekDays(DateTime d0, DateTime d1)
        {
            int ndays = 1 + Convert.ToInt32((d1 - d0).TotalDays);
            int nsaturdays = (ndays + Convert.ToInt32(d0.DayOfWeek)) / 7;
            return (double) (ndays - 2 * nsaturdays
                   - (d0.DayOfWeek == DayOfWeek.Sunday ? 1 : 0)
                   + (d1.DayOfWeek == DayOfWeek.Saturday ? 1 : 0));
        }
    }

}                        
namespace QuantConnect 
{   
    /*
    *   Example of how to use Put pricing with Black-Scholes in an algorithm
    *  		by: Jean-Paul van Brakel
    */
    public class BasicTemplateAlgorithm : QCAlgorithm
    {
    	// ticker to be used
    	private readonly string _ticker = "AAPL";
    	
    	// number of periods to be used in volatility calculation
    	private static int _vol_periods = 14;
    	private readonly RollingWindow<TradeBar> PriceHistory = new RollingWindow<TradeBar>(_vol_periods);
    	
    	// define option maturity date
    	private readonly DateTime _maturityDate = new DateTime(2015, 1, 16); // third friday of the month
    	
        //Initialize the data and resolution you require for your strategy:
        public override void Initialize() 
        {
            //Start and End Date range for the backtest:
            SetStartDate(2015, 1, 1); 
            SetWarmup(TimeSpan.FromDays(_vol_periods));
            SetEndDate(2015, 1, 2);
            
            //Cash allocation
            SetCash(25000);
            
            //Add as many securities as you like. All the data will be passed into the event handler:
            AddSecurity(SecurityType.Equity, _ticker, Resolution.Minute);
            
            //Initialise plot
			Chart plotter = new Chart("DerivativePlot", ChartType.Stacked);
	        plotter.AddSeries(new Series("Price", 		SeriesType.Line));
			plotter.AddSeries(new Series("Put price", 	SeriesType.Line));
			AddChart(plotter);
        }

        //Data Event Handler: New data arrives here.
        public void OnData(TradeBars data) 
        {   
        	PriceHistory.Add(data[_ticker]);
        	if (!PriceHistory.IsReady) return;
        	
        	// specify option settings here:
        	double price 		= (double)PriceHistory[0].Close;
        	double strike   	= 110;		// strike price of option
        	double rate 		= 0.05;		// risk-free rate of return to use in calculation
        	// recalculate annualised time to maturity
			double maturity 	= (BlackScholes.CountWeekDays(data.Time,_maturityDate)/250); 
			double[] _p_history = new double[PriceHistory.Count];
			for (int i = 0; i < PriceHistory.Count; i++)
				// copy close (you can change this to your liking)
				_p_history[i] = (double)PriceHistory[i].Close;
			// approximate volatility with historical volatility of the underlying
			double volatility 	= BlackScholes.HistoricalVolatility(_p_history); 
        	double yield 		= 0.01;		// approximation to the annualised dividend yields(%) for AAPL
        	
        	// calculate Black-Scholes option value for a European PUT (also approximation to American PUT)
        	double _optionPrice = BlackScholes.blsPut(price, strike, rate, maturity, volatility, yield);
        	
        	if (data.Time >= StartDate) {
				Plot("DerivativePlot", "Price", price);
            	Plot("DerivativePlot", "Put price", _optionPrice); 	
        	}
        	
        	// put your actual trading logic here:
        	if (!Portfolio.HoldStock) {
        		Order(_ticker, -100);
        	}
        }
    }
}