private void CommodityLookbackVanillaComparison(String ValuationDate = "2015-03-19", Double vol = 0.28, Double spot = 240, Double strike = 240, Boolean isCall = true, Boolean isFixed = true) { var valuationDate = DateFromStr(ValuationDate); var maturityDate = new Term("176D").Next(valuationDate); var calendar = CalendarImpl.Get("chn"); var obsDates = new[] { new Date(2015, 4, 2), new Date(2015, 5, 4), new Date(2015, 6, 2), new Date(2015, 7, 2), new Date(2015, 8, 3), new Date(2015, 9, 2) }; var option = new LookbackOption( valuationDate, maturityDate, OptionExercise.European, isCall ? OptionType.Call : OptionType.Put, isFixed ? StrikeStyle.Fixed : StrikeStyle.Floating, strike, InstrumentType.EquityIndex, calendar, new Act365(), CurrencyCode.CNY, CurrencyCode.CNY, new[] { maturityDate }, obsDates, new Dictionary <Date, double>(), notional: 1 ); var vanilla = new VanillaOption( valuationDate, maturityDate, OptionExercise.European, isCall ? OptionType.Call : OptionType.Put, strike, InstrumentType.EquityIndex, calendar, new Act365(), CurrencyCode.CNY, CurrencyCode.CNY, new[] { maturityDate }, obsDates, notional: 1 ); var market1 = TestMarket(referenceDate: ValuationDate, vol: vol, spot: spot); var market2 = TestMarket(referenceDate: ValuationDate, vol: vol * 0.8, spot: spot); var analyticalEngine = new AnalyticalLookbackOptionEngine(); var vanillaEngine = new AnalyticalVanillaEuropeanOptionEngine(); var analyticalResult = analyticalEngine.Calculate(option, market1, PricingRequest.All); var vanillaResult = vanillaEngine.Calculate(vanilla, market1, PricingRequest.All); var volResult = analyticalEngine.Calculate(option, market2, PricingRequest.All); //Floating Lookback Option >= ATM vanilla //High volatility Floating >= Low volatility Floating Assert.AreEqual(analyticalResult.Pv >= vanillaResult.Pv, true); Assert.AreEqual(analyticalResult.Pv >= volResult.Pv, true); }
private void CommodityLookbackOptionGreekCalc(String ValuationDate = "2015-03-19", Double vol = 0.28, Double spot = 240, Double strike = 240, Boolean isCall = true, Boolean isFixed = true, double expectedPv = 0.03368701153344, double expectedDelta = 0.431553260493781, double expectedGamma = 4319.00095926793, double expectedVega = 0.00146247323594882, double expectedRho = -1.62432084616776E-06, double expectedTheta = -0.000398443365606245 ) { var valuationDate = DateFromStr(ValuationDate); var maturityDate = new Term("176D").Next(valuationDate); var calendar = CalendarImpl.Get("chn"); var obsDates = new[] { new Date(2015, 4, 2), new Date(2015, 5, 4), new Date(2015, 6, 2), new Date(2015, 7, 2), new Date(2015, 8, 3), new Date(2015, 9, 2) }; var option = new LookbackOption( valuationDate, maturityDate, OptionExercise.European, isCall ? OptionType.Call : OptionType.Put, isFixed ? StrikeStyle.Fixed : StrikeStyle.Floating, strike, InstrumentType.EquityIndex, calendar, new Act365(), CurrencyCode.CNY, CurrencyCode.CNY, new[] { maturityDate }, obsDates, new Dictionary <Date, double>(), notional: 1 ); var market = TestMarket(referenceDate: ValuationDate, vol: vol, spot: spot); var analyticalEngine = new AnalyticalLookbackOptionEngine(); var analyticalResult = analyticalEngine.Calculate(option, market, PricingRequest.All); Assert.AreEqual(expectedPv, analyticalResult.Pv, 1e-8); Assert.AreEqual(expectedDelta, analyticalResult.Delta, 1e-8); Assert.AreEqual(expectedGamma, analyticalResult.Gamma, 1e-8); Assert.AreEqual(expectedVega, analyticalResult.Vega, 1e-8); Assert.AreEqual(expectedRho, analyticalResult.Rho, 1e-8); Assert.AreEqual(expectedTheta, analyticalResult.Theta, 1e-8); }
private void CommodityLookbackOptionPnLCalc(double vol = 0.28, double spot = 240, double strike = 240, Boolean isCall = true, Boolean isFixed = true, string t0 = "2015-03-19", string t1 = "2015-03-20", double volMove = 0.10, double mktMove = 1e-4, double toleranceInPct = 2) { var T0 = DateFromStr(t0); var T1 = DateFromStr(t1); var spotNew = spot + spot * mktMove; var volNew = vol + volMove; var maturityDate = new Term("176D").Next(T0); var calendar = CalendarImpl.Get("chn"); var obsDates = new[] { new Date(2015, 4, 2), new Date(2015, 5, 4), new Date(2015, 6, 2), new Date(2015, 7, 2), new Date(2015, 8, 3), new Date(2015, 9, 2) }; var valuationDay = t0; var valuationDayNew = t1; var option = new LookbackOption( T0, maturityDate, OptionExercise.European, isCall ? OptionType.Call : OptionType.Put, isFixed ? StrikeStyle.Fixed : StrikeStyle.Floating, strike, InstrumentType.EquityIndex, calendar, new Act365(), CurrencyCode.CNY, CurrencyCode.CNY, new[] { maturityDate }, obsDates, new Dictionary <Date, double>() ); var market = TestMarket(referenceDate: t0, vol: vol, spot: spot); var marketNew = TestMarket(referenceDate: t1, vol: volNew, spot: spotNew); var marketPI = TestMarket(referenceDate: t0, vol: vol, spot: spotNew); var marketVI = TestMarket(referenceDate: t0, vol: volNew, spot: spot); var marketPVC = TestMarket(referenceDate: t0, vol: volNew, spot: spotNew); var engine = new AnalyticalLookbackOptionEngine(); var result = engine.Calculate(option, market, PricingRequest.All); var resultNew = engine.Calculate(option, marketNew, PricingRequest.All); var resultPI = engine.Calculate(option, marketPI, PricingRequest.All); var resultVI = engine.Calculate(option, marketVI, PricingRequest.All); var resultPVC = engine.Calculate(option, marketPVC, PricingRequest.All); var actualPL = resultNew.Pv - result.Pv; //price Impact //PI = PV(t-1, priceNew) - Pv(t-1) var basePv = result.Pv; var PI = resultPI.Pv - basePv; var thetapl = result.Theta * (T1 - T0); //vol impact //VI = PV(t-1. volNew) - Pv (t-1) var VI = resultVI.Pv - basePv; //price vol cross impact //PVC = PV(t-1. volNew, PriceNew) - Pv (t-1) - (PI+VI) var PVC = resultPVC.Pv - basePv - PI - VI; var newEstimate = PI + VI + PVC + thetapl; var newUnexplained = actualPL - newEstimate; //Time impact //TI = PV(t, all OldInfo) - Pv(t-1) //TODO: //Time/ price cross Impact //TPC = PV(t, priceNew) - pv(t-1) - (TI +PI) //Time/vol cross impact //TVC = PV(t, volNew) - pv(t-1) -(TI+VI) //TODO: //in case of big move ( vol and spot), we need high order risk to explain pnl //var diff = actualPL - esimstatedPL; //Assert.AreEqual(true, Math.Abs(diff / actualPL) * 100.0 < toleranceInPct); //pnl well explained in not too extreme moves Assert.AreEqual(true, Math.Abs(newUnexplained / actualPL) * 100.0 < toleranceInPct); }
private void calculate_Click(object sender, RoutedEventArgs e) { this.sw.Reset(); this.sw.Start(); graphPlot = new GraphPlotting(); this.DataContext = graphPlot; this.graphs.IsEnabled = true; if (this.simulationNumber > 500 && this.steps > 500) { this.graphs.ToolTip = "Graph may take time to load "; } else { this.graphs.ToolTip = ""; } ISecurity underlying = new Stock(this.underlyingPrice); Options option = null; switch (this.kind) { case OptionKind.ASIAN: option = new AsianOption(underlying.Symbol, underlying, this.maturityDate, this.strike, this.vol, this.type, this.kind); break; case OptionKind.BARRIER: option = new BarrierOption(underlying.Symbol, underlying, this.maturityDate, this.strike, this.vol, this.type, this.kind, this.rebate, this.barrierOptiont); break; case OptionKind.DIGITAL: option = new DigitalOption(underlying.Symbol, underlying, this.maturityDate, this.strike, this.vol, this.type, this.kind, this.rebate); break; case OptionKind.EUROPEAN: option = new EuropeanOption(underlying.Symbol, underlying, this.maturityDate, this.strike, this.vol, this.type, this.kind); break; case OptionKind.LOOKBACK: option = new LookbackOption(underlying.Symbol, underlying, this.maturityDate, this.strike, this.vol, this.type, this.kind); break; case OptionKind.RANGE: option = new RangeOption(underlying.Symbol, underlying, this.maturityDate, this.strike, this.vol, this.type, this.kind); break; default: option = new EuropeanOption(underlying.Symbol, underlying, this.maturityDate, this.strike, this.vol, this.type, this.kind); break; } try { Task work = Task.Factory.StartNew(() => { this.Dispatcher.Invoke(() => this.progress.IsActive = true); option.calulateOptionPriceAndGreeks(this.simulationNumber, this.rate, this.steps, this.anitheticReductionEnabled, this.controlVariateEnabled, this.multithreadingEnabled, plot: this.graphPlot); this.sw.Stop(); this.Dispatcher.Invoke(() => { display(option); this.progress.IsActive = false; }); }); } catch (Exception message) { MessageBox.Show(message.Message.ToString() + "\n" + message.StackTrace.ToString()); } }
private void bPriceOptionBook_Click(object sender, RoutedEventArgs e) { graphPlot = new GraphPlotting(); graphs.DataContext = graphPlot; Task work = Task.Factory.StartNew(() => { var orderBook = model.OrderBookDBs.ToList(); foreach (var trade in orderBook) { if (trade.InstrumentsDB.SecurityTypeDB.TypeName.Equals("Stocks")) { var instrument = model.StockDBs.Where(x => x.Symbol == trade.InstrumentsDB.Symbol).First(); trade.FairPrice = trade.Price; trade.Delta = trade.Position == "BUY" ? trade.Quantity : -1 * trade.Quantity; trade.ProfitLoss = 0; trade.Theta = 0; trade.Gamma = 0; trade.Vega = 0; trade.Rho = 0; lock (lck) { model.SaveChanges(); } } else if (trade.InstrumentsDB.SecurityTypeDB.TypeName.Equals("Options")) { var instrument = model.OptionsDBs.Where(x => x.Symbol == trade.InstrumentsDB.Symbol).First(); Options option = null; ISecurity underlying = new Stock(instrument.StockDB.LastTradedPrice); switch (instrument.OptionKindDB.OptionKindName) { case "Asian Option": option = new AsianOption(instrument.Symbol, underlying, instrument.MaturityDate, (Double)instrument.StrikePrice, instrument.StockDB.HistoricalVolatility, instrument.OptionType == "CALL" ? OptionType.CALL : OptionType.PUT, OptionKind.ASIAN); break; case "Barrier Option": option = new BarrierOption(instrument.Symbol, underlying, instrument.MaturityDate, (Double)instrument.StrikePrice, instrument.StockDB.HistoricalVolatility, instrument.OptionType == "CALL" ? OptionType.CALL : OptionType.PUT, OptionKind.BARRIER, (Double)instrument.Barrier, (instrument.BarrierOptionType == "downout" ? BarrierOptionType.DOWNOUT : (instrument.BarrierOptionType == "downin" ? BarrierOptionType.DOWNIN : (instrument.BarrierOptionType == "upout" ? BarrierOptionType.UPOUT : BarrierOptionType.UPIN)))); break; case "Digital Option": option = new DigitalOption(instrument.Symbol, underlying, instrument.MaturityDate, (Double)instrument.StrikePrice, instrument.StockDB.HistoricalVolatility, instrument.OptionType == "CALL" ? OptionType.CALL : OptionType.PUT, OptionKind.DIGITAL, (Double)instrument.Rebate); break; case "European Option": option = new EuropeanOption(instrument.Symbol, underlying, instrument.MaturityDate, (Double)instrument.StrikePrice, instrument.StockDB.HistoricalVolatility, instrument.OptionType == "CALL" ? OptionType.CALL : OptionType.PUT, OptionKind.EUROPEAN); break; case "Lookback Option": option = new LookbackOption(instrument.Symbol, underlying, instrument.MaturityDate, (Double)instrument.StrikePrice, instrument.StockDB.HistoricalVolatility, instrument.OptionType == "CALL" ? OptionType.CALL : OptionType.PUT, OptionKind.LOOKBACK); break; case "Range Option": option = new RangeOption(instrument.Symbol, underlying, instrument.MaturityDate, (Double)instrument.StrikePrice, instrument.StockDB.HistoricalVolatility, instrument.OptionType == "CALL" ? OptionType.CALL : OptionType.PUT, OptionKind.RANGE); break; default: break; } try { option.calulateOptionPriceAndGreeks(1000, 0.05, (option.ExpiryDate - DateTime.Now).Days, true, option.OptionKind == OptionKind.EUROPEAN ? true : false, true, plot: graphPlot); trade.FairPrice = Math.Round(option.Price, 4); trade.ProfitLoss = Math.Round((Double)trade.FairPrice - (Double)trade.Price, 4) * (trade.Position == "BUY" ? trade.Quantity : -1 * trade.Quantity); trade.Delta = Math.Round(option.Greeks.Delta, 4) * (trade.Position == "BUY" ? trade.Quantity : -1 * trade.Quantity); trade.Theta = Math.Round(option.Greeks.Theta, 4) * (trade.Position == "BUY" ? trade.Quantity : -1 * trade.Quantity); trade.Gamma = Math.Round(option.Greeks.Gamma, 4) * (trade.Position == "BUY" ? trade.Quantity : -1 * trade.Quantity); trade.Vega = Math.Round(option.Greeks.Vega, 4) * (trade.Position == "BUY" ? trade.Quantity : -1 * trade.Quantity); trade.Rho = Math.Round(option.Greeks.Rho, 4) * (trade.Position == "BUY" ? trade.Quantity : -1 * trade.Quantity); lock (lck) { model.SaveChanges(); } } catch (Exception message) { MessageBox.Show(message.Message.ToString() + "\n" + message.StackTrace.ToString()); } } } this.Dispatcher.Invoke(() => { dataGrid.DataContext = orderBook; }); }); }