public override IPricingResult Calculate(ConvertibleBond convertibleBond, IMarketCondition market, PricingRequest request) { var result = new PricingResult(market.ValuationDate, request); if (convertibleBond.ConversionOption == null) { result.Pv = market.MktQuote.Value[convertibleBond.Bond.Id].Item2; } else { var optionParts = _optionEngine.Calculate(convertibleBond.ConversionOption, market.UpdateCondition( new UpdateMktConditionPack <IYieldCurve>(x => x.DiscountCurve, market.RiskfreeCurve.Value)), PricingRequest.All); //TODO: refactor calculation here //(jira: http://139.196.190.223:8888/browse/QDP-255) result.Pv = market.MktQuote.Value[convertibleBond.Bond.Id].Item2 - optionParts.Pv * convertibleBond.ConversionRatio; result.Delta = optionParts.Delta * convertibleBond.ConversionRatio; result.Gamma = optionParts.Gamma * convertibleBond.ConversionRatio; result.Vega = optionParts.Vega * convertibleBond.ConversionRatio; result.Rho = optionParts.Rho * convertibleBond.ConversionRatio; } //(jira: http://139.196.190.223:8888/browse/QDP-251) //Disable unnecessary and offending calc below //This will fail 14宝钢-E pricing and many other pricing when spot is high //var newMarket = market.UpdateCondition(new UpdateMktConditionPack<Dictionary<string, Tuple<PriceQuoteType, double>>>(x => x.MktQuote, market.MktQuote.Value.UpdateKey(convertibleBond.Bond.Id, Tuple.Create(PriceQuoteType.Dirty, result.Pv)))); //var zeroSpread = BondPricingFunctions.ZeroSpread(convertibleBond.Bond, newMarket); //var bondMarket = // market.UpdateCondition(new UpdateMktConditionPack<IYieldCurve>(x => x.DiscountCurve, // market.DiscountCurve.Value.GetSpreadedCurve(new ZeroSpread(zeroSpread)))); //var bondEngine = new BondEngine(); //var bondResults = bondEngine.Calculate(convertibleBond.Bond, bondMarket, PricingRequest.All); return(result); }
public void C7_11_2_ReverseConvertibleBondOnEquityBasket() { var cb = new ConvertibleBond(OptionType.Put, 5, 100, 0, 0, 0.2); cb.Basket.Add(new Equity() { Price = 100, Volatility = 0.2 }, 0.5); cb.Basket.Add(new Equity() { Price = 100, Volatility = 0.2 }, 0.5); var correlations = new Matrix <double>(2, 2); correlations[1, 1] = 0.8; correlations[1, 2] = 1; correlations[2, 1] = 1; correlations[2, 1] = 0.8; var price = cb.Price(100, correlations); Console.WriteLine(price); }
private static ConvertibleBondAnalytics computeAnalytics(IMarketCondition market, ConvertibleBond cb, double putRedemptionPrice) { //analytics part var cbSpot = market.MktQuote.Value[cb.Bond.Id].Item2; var stockPrice = market.SpotPrices.Value.Values.First(); var conversionValue = stockPrice * cb.ConversionRatio; var premiumToShareInPct = (cbSpot / conversionValue - 1) * 100; // in Pct var arbitragePL = conversionValue - cbSpot; //buy cb, sell stock var timeToMaturity = (cb.UnderlyingMaturityDate - market.ValuationDate) / 365.0; //bond analytics var bondengine = new BondEngine(); var yieldToMaturity = bondengine.Calculate(cb.Bond, market, PricingRequest.Ytm).Ytm * 100.0; var bondFloor = bondengine.Calculate(cb.Bond, market, PricingRequest.Pv).Pv; double premiumToBondInPct = (cbSpot / bondFloor - 1) * 100; //in Pct //parity vs bond floor premium var parityFloorPremiumInPct = (conversionValue / bondFloor - 1) * 100.0; //option analytics var impliedOptionValue = cbSpot - bondFloor; var impliedUnitOptionPremium = impliedOptionValue / cb.ConversionRatio; var option = createOption(strike: cb.ConversionOption.Strike, expiry: cb.ConversionOption.UnderlyingMaturityDate, firstConversionDate: cb.ConversionOption.StartDate, American: false); var engine = new AnalyticalVanillaEuropeanOptionEngine(); var impliedVol = engine.ImpliedVol(option, market, impliedUnitOptionPremium); //Note: assume simple calc here: putPrice 103, current price 109.69, then if we can put the bond now, returnOnPut = (103 - 109.69)/109.69 var returnOnPut = (putRedemptionPrice / cbSpot - 1.0) * 100; //cb style based on parity/ bond floor relationship //if parity is worth 20% more than bond floor, then stock like //if parity is worth -20% less than bond floor, then bond like //otherwise, cb is in balance mode var cbStatus = ConvertibleBondStatus.Balance; if (parityFloorPremiumInPct > 20) { cbStatus = ConvertibleBondStatus.StockLike; } else if (parityFloorPremiumInPct < -20) { cbStatus = ConvertibleBondStatus.BondLike; } return(new ConvertibleBondAnalytics( conversionValue: conversionValue, premiumToShareInPct: premiumToShareInPct, arbitragePL: arbitragePL, timeToMaturity: timeToMaturity, yieldToMaturity: yieldToMaturity, bondFloor: bondFloor, premiumToBondInPct: premiumToBondInPct, parityFloorPremiumInPct: parityFloorPremiumInPct, optionValue: impliedOptionValue, impliedVol: impliedVol, returnOnPut: returnOnPut, cbStatus: cbStatus)); }