/// <summary> /// Populates CallPriceMarketData data structure from options /// quotes and additional calls to market data. /// </summary> /// <param name="provider">The underlying market data provider.</param> /// <param name="mdq">The underlying query.</param> /// <param name="quotes">The options quotes list.</param> /// <param name="data">The data structure to be populated.</param> /// <returns>The status of the operation.</returns> public static RefreshStatus GetCallPriceMarketData(IMarketDataProvider provider, MarketDataQuery mdq, List <IOptionQuote> quotes, Fairmat.MarketData.CallPriceMarketData data) { // Gets call options. var calls = quotes.FindAll(x => x.Type == OptionQuoteType.Call); var puts = quotes.FindAll(x => x.Type == OptionQuoteType.Put); // Get maturities and strikes. var maturtiesDates = quotes.Select(item => item.Maturity).Distinct().OrderBy(x => x).ToList(); var strikes = quotes.Select(item => item.Strike).Distinct().OrderBy(x => x).ToList(); data.Strike = (Vector)strikes.ToArray(); //var callMaturtiesDates = calls.Select(item => item.MaturityDate).Distinct().ToList(); Console.WriteLine("Maturities"); data.Maturity = new Vector(maturtiesDates.Count); for (int z = 0; z < maturtiesDates.Count; z++) { data.Maturity[z] = RightValueDate.DatesDifferenceCalculator(mdq.Date, maturtiesDates[z]); } data.CallPrice = new Matrix(data.Maturity.Length, data.Strike.Length); var putPrices = new Matrix(data.Maturity.Length, data.Strike.Length); // Group maturities, calls, puts with respect to strikes. Dictionary <double, Tuple <List <double>, List <double>, List <double> > > atm = new Dictionary <double, Tuple <List <double>, List <double>, List <double> > >(); for (int si = 0; si < data.Strike.Length; si++) { for (int mi = 0; mi < maturtiesDates.Count; mi++) { IOptionQuote callQuote = calls.Find(x => x.Strike == data.Strike[si] && x.Maturity == maturtiesDates[mi]); if (callQuote != null) { data.CallPrice[mi, si] = callQuote.Price; } IOptionQuote putQuote = puts.Find(x => x.Strike == data.Strike[si] && x.Maturity == maturtiesDates[mi]); if (putQuote != null) { putPrices[mi, si] = putQuote.Price; } if (callQuote != null && putQuote != null) { Tuple <List <double>, List <double>, List <double> > element = null; if (atm.ContainsKey(data.Strike[si])) { element = atm[data.Strike[si]]; } else { element = new Tuple <List <double>, List <double>, List <double> >(new List <double>(), new List <double>(), new List <double>()); atm.Add(data.Strike[si], element); } element.Item1.Add(data.Maturity[mi]); element.Item2.Add(callQuote.Price); element.Item3.Add(putQuote.Price); } } } Console.WriteLine("CallPrices"); Console.WriteLine(data.CallPrice); Console.WriteLine("Putprices"); Console.WriteLine(putPrices); // Request the spot price . var mdq2 = DVPLI.ObjectSerialization.CloneObject(mdq) as MarketDataQuery; mdq2.MarketDataType = typeof(Scalar).ToString(); IMarketData s0; var s0Result = provider.GetMarketData(mdq2, out s0); if (s0Result.HasErrors) { return(s0Result); } data.S0 = (s0 as Scalar).Value; // Load atm info (get the strike with the higher number of elements). int maxElements = -1; double argMax = -1; // Keeps the Strike-Spot distance. double spotDistance = double.MaxValue; // Find the options which minimize the distance from strike price and spot price. foreach (double strike in atm.Keys) { double distance = Math.Abs(strike - data.S0); if (distance < spotDistance) { spotDistance = distance; maxElements = atm[strike].Item1.Count; argMax = strike; } } if (spotDistance != double.MaxValue) { data.StrikeATM = argMax; data.MaturityATM = (Vector)atm[argMax].Item1.ToArray(); data.CallPriceATM = (Vector)atm[argMax].Item2.ToArray(); data.PutPriceATM = (Vector)atm[argMax].Item3.ToArray(); } else { Console.WriteLine("Cannot find atm information"); } data.Ticker = mdq.Ticker; data.Market = mdq.Market; data.Date = mdq.Date; return(new RefreshStatus()); }