/// <summary> /// 计算隐含波动率 /// </summary> /// <param name="underlyingPrice"></param> /// <param name="strikePrice"></param> /// <param name="daysToMaturity"></param> /// <param name="interestRate"></param> /// <param name="marketPrice"></param> /// <param name="optionType"></param> /// <returns></returns> public static double CalculateImpliedVolatilityBisection(double underlyingPrice, double strikePrice, int daysToMaturity, double interestRate, double marketPrice, OptionTypeEnum optionType) { double lower = 0; double upper = 10; double impliedVolatility = 0; double impliedPrice = 0; while (Math.Abs(upper - lower) > 0.000000001) { impliedVolatility = (lower + upper) / 2; OptionPricingModelParams optionPricingModelParams = new OptionPricingModelParams(optionType, underlyingPrice, strikePrice, interestRate, impliedVolatility, daysToMaturity); OptionValue optionValue = OptionPricingModel.EuropeanBS(optionPricingModelParams); if(impliedPrice == optionValue.Price) { break; } impliedPrice = optionValue.Price; if (optionValue.Price >= marketPrice) { upper = impliedVolatility; } else { lower = impliedVolatility; } } return impliedVolatility; }
/// <summary> /// 期权定价模型 /// </summary> /// <param name="optionProperties"></param> /// <returns></returns> public static OptionValue EuropeanBS(OptionPricingModelParams optionProperties) { double sigmaTimesSqrtMaturity = optionProperties.Volatility * Math.Sqrt(optionProperties.Maturity); double d1 = (Math.Log(optionProperties.UnderlyingPrice / optionProperties.StrikePrice) + (optionProperties.Volatility * optionProperties.Volatility / 2) * optionProperties.Maturity) / sigmaTimesSqrtMaturity; if (double.IsNaN(d1)) { d1 = Double.PositiveInfinity; } double d2 = d1 - sigmaTimesSqrtMaturity; double optionPrice = 0; double delta = 0; double gamma = 0; double vega = 0; double theta = 0; double rho = 0; switch (optionProperties.OptionType) { case OptionTypeEnum.call: optionPrice = optionProperties.UnderlyingPrice * Math.Exp(-optionProperties.InterestRate * optionProperties.Maturity) * normdist(d1) - normdist(d2) * optionProperties.StrikePrice * Math.Exp(-optionProperties.InterestRate * optionProperties.Maturity); delta = Math.Exp(-optionProperties.InterestRate * optionProperties.Maturity) * normdist(d1); gamma = ((Math.Exp(-d1 * d1 / 2) / Math.Sqrt(2 * Math.PI)) * Math.Exp(-optionProperties.InterestRate * optionProperties.Maturity)) / (optionProperties.UnderlyingPrice * optionProperties.Volatility * Math.Sqrt(optionProperties.Maturity)); vega = (Math.Exp(-d1 * d1 / 2) / Math.Sqrt(2 * Math.PI)) * Math.Exp(-optionProperties.InterestRate * optionProperties.Maturity) * optionProperties.UnderlyingPrice * Math.Sqrt(optionProperties.Maturity); theta = optionProperties.InterestRate * optionPrice - Math.Exp(-optionProperties.InterestRate * optionProperties.Maturity) * optionProperties.UnderlyingPrice * (Math.Exp(-d1 * d1 / 2) / Math.Sqrt(2 * Math.PI)) * optionProperties.Volatility / (2 * Math.Sqrt(optionProperties.Maturity)); rho = -optionProperties.Maturity * optionPrice; break; case OptionTypeEnum.put: optionPrice = -optionProperties.UnderlyingPrice * Math.Exp(-optionProperties.InterestRate * optionProperties.Maturity) * normdist(-d1) + normdist(-d2) * optionProperties.StrikePrice * Math.Exp(-optionProperties.InterestRate * optionProperties.Maturity); delta = Math.Exp(-optionProperties.InterestRate * optionProperties.Maturity) * (normdist(d1) - 1); gamma = ((Math.Exp(-d1 * d1 / 2) / Math.Sqrt(2 * Math.PI)) * Math.Exp(-optionProperties.InterestRate * optionProperties.Maturity)) / (optionProperties.UnderlyingPrice * optionProperties.Volatility * Math.Sqrt(optionProperties.Maturity)); vega = (Math.Exp(-d1 * d1 / 2) / Math.Sqrt(2 * Math.PI)) * Math.Exp(-optionProperties.InterestRate * optionProperties.Maturity) * optionProperties.UnderlyingPrice * Math.Sqrt(optionProperties.Maturity); theta = optionProperties.InterestRate * optionPrice - Math.Exp(-optionProperties.InterestRate * optionProperties.Maturity) * optionProperties.UnderlyingPrice * (Math.Exp(-d1 * d1 / 2) / Math.Sqrt(2 * Math.PI)) * optionProperties.Volatility / (2 * Math.Sqrt(optionProperties.Maturity)); rho = optionProperties.Maturity * optionPrice; break; default: break; } switch (GlobalValues.TimeMeasurementType) { case TimeMeasurementTypeEnum.交易日: theta /= GlobalValues.TradingDaysPerYear; break; case TimeMeasurementTypeEnum.日历日: theta /= GlobalValues.GeneralDaysPerYear; break; default: break; } return new OptionValue(optionPrice, delta, gamma, vega / 100, theta, rho / 100, optionProperties.Maturity); }
/// <summary> /// 有行情到来时的处理逻辑 /// </summary> /// <param name="md"></param> private void MD_OnTick(ThostFtdcDepthMarketDataField md) { if (this.option.InstrumentID == md.InstrumentID) { this.option.LastMarket = md; //计算期权理论价格 OptionPricingModelParams optionPricingModelParams = new OptionPricingModelParams(this.option.OptionType, MainForm.Future.LastMarket.LastPrice, this.option.StrikePrice, GlobalValues.InterestRate, GlobalValues.Volatility, StaticFunction.GetDaysToMaturity(this.option.InstrumentID)); this.option.OptionValue = OptionPricingModel.EuropeanBS(optionPricingModelParams); ////计算隐含波动率 if (MainForm.Future.LastMarket != null) { this.option.ImpliedVolatility = StaticFunction.CalculateImpliedVolatilityBisection(MainForm.Future.LastMarket.LastPrice, this.option.StrikePrice, StaticFunction.GetDaysToMaturity(this.option.InstrumentID), GlobalValues.InterestRate, md.LastPrice, this.option.OptionType); string[] updateDateTimeString = md.UpdateTime.Split(':'); DateTime updateDateTime = new DateTime(); updateDateTime = updateDateTime.AddHours(double.Parse(updateDateTimeString[0])); updateDateTime = updateDateTime.AddMinutes(double.Parse(updateDateTimeString[1])); updateDateTime = updateDateTime.AddSeconds(double.Parse(updateDateTimeString[2])); if ((updateDateTime - lastUpdateDateTime).TotalSeconds > this.ReplaceOrderDuration) { //撤单 this.CancelOrder(); //计算报价 double[] quote = this.CalculateQuote(); if (isRunning) { this.ReplaceOrderDuration = 11; this.lastUpdateDateTime = updateDateTime; this.PlaceOrder(quote); } else if (hasForQuote) { this.ReplaceOrderDuration = 11; this.lastUpdateDateTime = updateDateTime; hasForQuote = false; this.PlaceOrder(quote); } } } } }
/// <summary> /// Put行情更新时该方法被调用 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void put_MarketUpdated(object sender, EventArgs e) { //计算期权相关值 if (put.MarketData != null && underlying.MarketData != null) { //计算期权理论价格 OptionPricingModelParams optionPricingModelParams = new OptionPricingModelParams(this.put.OptionType, this.underlying.MarketData.LastPrice, this.put.StrikePrice, GlobalValues.InterestRate, GlobalValues.Volatility, StaticFunction.GetDaysToMaturity(this.put.Contract.InstrumentID)); this.put.OptionValue = OptionPricingModel.EuropeanBS(optionPricingModelParams); //计算隐含波动率 this.put.ImpliedVolatility = StaticFunction.CalculateImpliedVolatilityNewton(this.underlying.MarketData.LastPrice, this.put.StrikePrice, StaticFunction.GetDaysToMaturity(this.put.Contract.InstrumentID), GlobalValues.InterestRate, this.put.MarketData.LastPrice, this.put.OptionType); } }