public double GetProbabilityByPrice(double price) { int count = Prices.Count; int probabilityIndex = Prices.BinarySearch(price); if (probabilityIndex < 0) { int largerIndex = ~probabilityIndex; int smallerIndex = largerIndex - 1; if (largerIndex == count) { return(1 - Probabilities[count - 1]); } // Do linear interpolation double largerIdexProbability = Probabilities[largerIndex]; double smallerIdexProbability = Probabilities[smallerIndex]; double resultProbability = MarketMath.DoLinearInterpolation(Prices[smallerIndex], Prices[largerIndex], smallerIdexProbability, largerIdexProbability, price); resultProbability = 1 - resultProbability; return(resultProbability); } double stdDevProbability = 1 - Probabilities[probabilityIndex]; return(stdDevProbability); }
public Prediction GetPrediction(IBasicPredictionCalculationData data, double daysInFuture) { double volatility = data.GetVolatility(daysInFuture); Prediction prediction = MarketMath.GetSymmetricPrediction(data.LastPrice, volatility, data.InterestRate, daysInFuture); return(prediction); }
public Dictionary <DateAndNumberOfDaysUntil, Prediction> MakePredictionsForDates(IBasicPredictionCalculationData data, IEnumerable <DateAndNumberOfDaysUntil> dates) { Dictionary <DateAndNumberOfDaysUntil, Prediction> predictions = new Dictionary <DateAndNumberOfDaysUntil, Prediction>(); foreach (DateAndNumberOfDaysUntil date in dates) { double daysInFuture = date.TotalNumberOfDaysUntilExpiry; if (daysInFuture.AlmostEqual(0) || daysInFuture < 0) { continue; } double volatility = data.GetVolatility(daysInFuture); Prediction prediction = MarketMath.GetSymmetricPrediction(data.LastPrice, volatility, data.InterestRate, daysInFuture); predictions.Add(date, prediction); } return(predictions); }
public EntityResponse <List <OptionQuotation> > GetOptionQuotes(List <string> optionNumbers) { EntityResponse <List <OptionQuotation> > results = GetOptionQuotesByOptionNumbers(optionNumbers); if (!results.IsSuccess) { return(results); } foreach (OptionQuotation quote in results.Entity) { EntityResponse <OptionBasicInformation> basic = GetOptionInformation(quote.OptionNumber); if (basic.IsSuccess) { quote.SecurityCode = basic.Entity.OptionUnderlyingCode; decimal?stockPrice; double daysToMaturity = _marketWorkTimeService.GetNumberOfDaysLeftUntilExpiry(basic.Entity.ExpireDate).TotalNumberOfDaysUntilExpiry; if (!MemoryCache.IsStockQuoteInfoCacheExpired(quote.SecurityCode)) { stockPrice = MemoryCache.StockQuoteInfoCache[quote.SecurityCode].StockQuoteInfos.LastPrice; } else { var stockQuoteInfo = GetStockQuote(basic.Entity.OptionUnderlyingCode).Entity; stockPrice = stockQuoteInfo.LastPrice; MemoryCache.AddOrUpdateStockQuoteInfoCache(quote.SecurityCode, stockQuoteInfo); } //decimal? stockPrice = GetStockQuote(basic.Entity.OptionUnderlyingCode).Entity.LastPrice; double spotPrice = 0; if (stockPrice != null) { spotPrice = (double)stockPrice; } quote.Greeks = MarketMath.GetGreeks(daysToMaturity, (double)basic.Entity.StrikePrice, _riskFreeRateProvider.GetRiskFreeRate(), spotPrice, quote.Ask, quote.Bid, quote.LatestTradedPrice, basic.Entity.OptionType == OptionType.Call ? LegType.Call : LegType.Put); } } return(results); }
public void UpdateQuotation(IEnumerable <OptionQuotation> quotations) { foreach (OptionQuotation optionQuotation in quotations) { Option option = this[optionQuotation.OptionNumber]; if (option != null) { optionQuotation.SecurityCode = option.SecurityCode; optionQuotation.OptionName = option.OptionName; optionQuotation.OptionCode = option.OptionCode; Mapper.Map(optionQuotation, option); option.Name = optionQuotation.OptionName; option.Greeks = MarketMath.GetGreeks(option.RootPair.Expiry.TotalNumberOfDaysUntilExpiry, option.RootPair.StrikePrice, RiskFreeRate, UnderlyingCurrentPrice, option.Ask, option.Bid, option.LatestTradedPrice, option.LegType); } } }
private static List <CoveredCall> GetCoveredCallsByLegType(OptionChain data, Dictionary <DateAndNumberOfDaysUntil, Prediction> predictions, /*EarningsCalendar calendar,*/ LegType legType, /*Signal volOfVol,*/ double?minimumPremiumParam, double?minimumReturnParam) { double minimumPremium = minimumPremiumParam ?? DefaultMinimumPremium; double minimumReturn = minimumReturnParam ?? DefaultMinimumReturn; HashSet <DateTime> optimalIsFound = new HashSet <DateTime>(); List <CoveredCall> coveredCalls = new List <CoveredCall>(); foreach (OptionPair optionChain in data) { Option option = legType == LegType.Call ? optionChain.CallOption : optionChain.PutOption; double bid = option.Bid; double currentPremium = bid; DateAndNumberOfDaysUntil expiry = optionChain.Expiry; double lastPrice = data.UnderlyingCurrentPrice; double strkePrice = optionChain.StrikePrice; List <OptionPair> chainsWithTheSameExpiry = data.Where(x => x.Expiry == expiry).ToList(); // todo: optionChain.OptionType //bool typeisSuitable = optionChain.OptionType == OptionType.Standard; double daysQuantity = expiry.TotalNumberOfDaysUntilExpiry; // Ignore expired options if (daysQuantity < 0 || daysQuantity.AlmostEqual(0) /*|| !typeisSuitable*/) { continue; } bool strikePriceIsSuitable = legType == LegType.Call ? optionChain.StrikePrice > lastPrice : optionChain.StrikePrice < lastPrice; if (!strikePriceIsSuitable) { // Check if fifth strike is suitable strikePriceIsSuitable = legType == LegType.Call ? chainsWithTheSameExpiry.Where(x => x.StrikePrice < lastPrice) .OrderBy(x => lastPrice - x.StrikePrice) .Take(5).Last().StrikePrice <optionChain.StrikePrice : chainsWithTheSameExpiry.Where(x => x.StrikePrice > lastPrice) .OrderBy(x => x.StrikePrice - lastPrice) .Take(5).Last().StrikePrice> optionChain.StrikePrice; } if (!strikePriceIsSuitable) { continue; } double intrinsicValue = legType == LegType.Call ? lastPrice > optionChain.StrikePrice ? lastPrice - optionChain.StrikePrice : 0 : lastPrice < optionChain.StrikePrice ? optionChain.StrikePrice - lastPrice : 0; double currentReturn = (Math.Pow(1 + (currentPremium - intrinsicValue) / lastPrice, 365.0 / daysQuantity) - 1) * 100; bool firstAboveBelowStdDev = false; Prediction prediction = predictions[optionChain.Expiry]; StdDevPrices stdDev = prediction.GetStdDevPrices(1); bool deviationIsSuitable = legType == LegType.Call ? strkePrice > stdDev.UpPrice : strkePrice < stdDev.DownPrice; if (deviationIsSuitable) { firstAboveBelowStdDev = legType == LegType.Call ? chainsWithTheSameExpiry .Where(x => x.StrikePrice >= stdDev.UpPrice) .Select(y => y.StrikePrice - stdDev.UpPrice) .Min() .AlmostEqual(strkePrice - stdDev.UpPrice) : chainsWithTheSameExpiry .Where(x => x.StrikePrice <= stdDev.DownPrice) .Select(y => stdDev.DownPrice - y.StrikePrice) .Min() .AlmostEqual(stdDev.DownPrice - optionChain.StrikePrice); } double probability = prediction.GetProbabilityByPrice(optionChain.StrikePrice) * 100; double probabilityInSigmas = MarketMath.GetSigmaProbabilityByDeviation(probability / 100); CoveredCall coveredCall = new CoveredCall(); coveredCall.Premium = currentPremium; coveredCall.Return = currentReturn; coveredCall.OptionNumber = option.OptionNumber; coveredCall.Probability = probability; coveredCall.ProbabilityInSigmas = probabilityInSigmas; // if (volOfVol != null) // { // coveredCall.VolOfVol = volOfVol.Value; // } coveredCall.PercentAboveBelowCurrentPrice = Math.Abs((optionChain.StrikePrice - lastPrice)) / lastPrice * 100; int numberOfStrikes = legType == LegType.Call ? chainsWithTheSameExpiry.Where(x => x.StrikePrice >= lastPrice) .OrderBy(x => x.StrikePrice) .ToList() .FindIndex(x => x.StrikePrice.AlmostEqual(optionChain.StrikePrice)) + 1 : chainsWithTheSameExpiry.Where(x => x.StrikePrice <= lastPrice) .OrderByDescending(x => x.StrikePrice) .ToList() .FindIndex(x => x.StrikePrice.AlmostEqual(optionChain.StrikePrice)) + 1; coveredCall.NumberOfStrikesBelowAboveCurrentPrice = numberOfStrikes; coveredCall.NumberOfSdBelowAboveCurrentPrice = probabilityInSigmas; // coveredCall.HasEarnings = calendar != null && calendar.Date >= DateTime.Now && calendar.Date <= optionChain.Expiry; // if (calendar != null) // { // coveredCall.DaysQuantityBeforeEarnings = (calendar.Date - DateTime.UtcNow).TotalDays; // } coveredCalls.Add(coveredCall); if (bid.AlmostEqual(0.0)) { coveredCall.RiskTolerance = RiskTolerance.NoBid; continue; } if (!deviationIsSuitable) { if (currentPremium < minimumPremium) { coveredCall.RiskTolerance = RiskTolerance.LowPremium; continue; } coveredCall.RiskTolerance = currentReturn >= minimumReturn ? RiskTolerance.Aggressive : RiskTolerance.LowReturn; continue; } if (currentPremium < minimumPremium) { coveredCall.RiskTolerance = RiskTolerance.LowPremium; continue; } if (currentReturn < minimumReturn) { coveredCall.RiskTolerance = RiskTolerance.LowReturn; continue; } if (!optimalIsFound.Contains(optionChain.Expiry.FutureDate) && daysQuantity >= 3 && daysQuantity <= 60 //&& (!coveredCall.HasEarnings || daysQuantity < coveredCall.DaysQuantityBeforeEarnings) && firstAboveBelowStdDev) { coveredCall.RiskTolerance = RiskTolerance.Optimal; optimalIsFound.Add(optionChain.Expiry.FutureDate); } else { coveredCall.RiskTolerance = RiskTolerance.Conservative; } } return(coveredCalls); }