Example #1
0
        // todo: consider to remove from here
        public DateAndNumberOfDaysUntil GetNumberOfDaysLeftUntilExpiry(DateTime expiry)
        {
            int delta = 0;
            EntityResponse <DateTime> utcMarketCloseTimeForDate = GetUtcMarketCloseTimeForDate(expiry);

            if (utcMarketCloseTimeForDate == null)
            {
                delta = -1;
            }

            if (expiry.Kind == DateTimeKind.Utc)
            {
                expiry = TimeZoneInfo.ConvertTimeFromUtc(expiry, CstTimeZone);
            }

            DateTime utcMarketCloseTime = TimeZoneInfo.ConvertTimeToUtc(expiry.Date.Add(SseCloseTime), CstTimeZone);
            TimeSpan diff = (utcMarketCloseTime - DateTime.UtcNow);
            DateAndNumberOfDaysUntil result = new DateAndNumberOfDaysUntil
            {
                FutureDate = expiry,
                TotalNumberOfDaysUntilExpiry = diff.TotalDays + delta
            };

            return(result);
        }
        private double?GetStrikePriceForLegOld(OptionChain chain, StrategyLeg leg, DateAndNumberOfDaysUntil date)
        {
            if (leg == null || leg.LegType == LegType.Security)
            {
                return(null);
            }
            IList <double> strikePrices = chain.GetStrikePrices(date);

            if (leg.BuyOrSell == BuyOrSell.Buy)
            {
                double strikePrice = leg.LegType == LegType.Call ?
                                     strikePrices.LastAndIndex(d => d < chain.UnderlyingCurrentPrice).Item2 :
                                     strikePrices.FirstAndIndex(d => d > chain.UnderlyingCurrentPrice).Item2;
                return(strikePrice);
            }
            else
            {
                List <DateAndStandardDeviation> stdDevs = _predictionAndStdDevService.GetExpiriesAndStandardDeviations(chain, chain.ExpirationDates, 1.0);
                DateAndStandardDeviation        stdDevPricesForCurrentExpiry = stdDevs.Single(d => d.DateAndNumberOfDaysUntil.FutureDate.Equals(date.FutureDate));
                double strikePrice = leg.LegType == LegType.Call
                                        ? strikePrices.GetClosest(stdDevPricesForCurrentExpiry.StdDev.UpPrice)
                                        : strikePrices.GetClosest(stdDevPricesForCurrentExpiry.StdDev.DownPrice);
                return(strikePrice);
            }
        }
        public List <DateAndStandardDeviations> GetStandardDeviationsForDates(IBasicPredictionCalculationData data, IReadOnlyList <DateAndNumberOfDaysUntil> referencePoints, IReadOnlyList <double> deviations)
        {
            const int numberOfPointsBetween = 4;

            DateAndNumberOfDaysUntil expirationDateForToday = _marketWorkTimeService.GetNumberOfDaysLeftUntilExpiry(_marketWorkTimeService.NowInMarketTimeZone.Date);

            List <DateAndNumberOfDaysUntil> experies = referencePoints.Union(expirationDateForToday.Yield()).Distinct().OrderBy(t => t.FutureDate).ToList();
            List <DateAndNumberOfDaysUntil> dates    = new List <DateAndNumberOfDaysUntil>(experies);

            for (int i = 0; i < experies.Count - 1; i++)
            {
                DateAndNumberOfDaysUntil current = experies[i];
                DateAndNumberOfDaysUntil next    = experies[i + 1];

                double range = next.TotalNumberOfDaysUntilExpiry - current.TotalNumberOfDaysUntilExpiry;
                if (range < 3)
                {
                    continue;
                }
                double step = Math.Round(range / numberOfPointsBetween, 3, MidpointRounding.AwayFromZero);

                // uniformly inserts points between current date and next date.
                IEnumerable <int> increments = CollectionExtensions.Range(0, range - step, step).Where(d => (int)d != 0).Select(d => (int)d).Distinct();
                foreach (int increment in increments)
                {
                    DateTime date = current.FutureDate.AddDays(increment);
                    dates.Add(_marketWorkTimeService.GetNumberOfDaysLeftUntilExpiry(date));
                }
            }

            List <DateAndNumberOfDaysUntil> datesToBuildPredictionFor = dates.OrderBy(e => e.FutureDate).ToList();

            Dictionary <DateAndNumberOfDaysUntil, Prediction> predictions = MakePredictionsForDates(data, datesToBuildPredictionFor);
            List <DateAndStandardDeviations> stdDevs = GetStandardDeviationsForDates(data, predictions, deviations);

            return(stdDevs);
        }
        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);
        }
Example #5
0
        public List <BasePortfolioItemGroupViewModel> GetPortfolioData(string customerCode, string accountCode, string tradeAccount)
        {
            #region Fetch data
            OptionPositionsArguments arguments = new OptionPositionsArguments
            {
                CustomerCode        = customerCode,
                CustomerAccountCode = accountCode
            };

            EntityResponse <List <OptionPositionInformation> >          optionPositions = _portfolioManager.GetOptionPositions(arguments);
            EntityResponse <List <OptionableStockPositionInformation> > stockPositions  = _portfolioManager.GetOptionalStockPositions(customerCode, accountCode, tradeAccount);

            if (!optionPositions.IsSuccess || !stockPositions.IsSuccess || optionPositions.Entity.Count == 0)
            {
                return(new List <BasePortfolioItemGroupViewModel>());
            }

            IEnumerable <PortfolioOption> portfolioOptions = Mapper.Map <List <OptionPositionInformation>, List <PortfolioOption> >(optionPositions.Entity);
            IEnumerable <PortfolioStock>  portfolioStocks  = Mapper.Map <List <OptionableStockPositionInformation>, List <PortfolioStock> >(stockPositions.Entity);
            Dictionary <string, EntityResponse <OptionChain> > optionChains = new Dictionary <string, EntityResponse <OptionChain> >();
            #endregion

            #region Fill additional information

            foreach (PortfolioOption portfolioItem in portfolioOptions)
            {
                EntityResponse <List <OptionBasicInformation> > optionBasicInformation = _marketDataProviderQueryable.GetOptionBasicInformation(optionNumber: portfolioItem.OptionNumber);

                if (optionBasicInformation.Entity == null || !optionBasicInformation.Entity.Any())
                {
                    continue;
                }

                OptionBasicInformation basicInfo = optionBasicInformation.Entity.Single();

                DateTime expiryDate             = basicInfo.ExpireDate;
                DateAndNumberOfDaysUntil expiry = _marketWorkTimeService.GetNumberOfDaysLeftUntilExpiry(expiryDate);

                portfolioItem.Expiry         = expiry;
                portfolioItem.UnderlyingCode = basicInfo.OptionUnderlyingCode;
                portfolioItem.UnderlyingName = basicInfo.OptionUnderlyingName;
                portfolioItem.StrikePrice    = basicInfo.StrikePrice;


                EntityResponse <OptionChain> optionChain;
                string underlying = portfolioItem.UnderlyingCode;

                if (optionChains.ContainsKey(underlying))
                {
                    optionChain = optionChains[underlying];
                }
                else
                {
                    optionChain = _marketDataService.GetOptionChain(underlying);
                    optionChains.Add(underlying, optionChain);
                }

                if (optionChain == null)
                {
                    continue;
                }

                Option option = optionChain.Entity[portfolioItem.OptionNumber];
                if (option == null)
                {
                    portfolioItem.UnderlyingCode = null;
                    continue;
                }
                Greeks greeks = option.Greeks ?? new Greeks();

                portfolioItem.LastPrice         = (decimal)option.LatestTradedPrice;         //optionChain.Entity.UnderlyingCurrentPrice;
                portfolioItem.PremiumMultiplier = option.RootPair.PremiumMultiplier;
                portfolioItem.Greeks            = new PortfolioGreeks(portfolioItem.OptionAvailableQuantity, greeks, portfolioItem.OptionSide, portfolioItem.PremiumMultiplier);
            }

            portfolioOptions = portfolioOptions.Where(x => x.UnderlyingCode != null);

            foreach (PortfolioStock portfolioStock in portfolioStocks)
            {
                SecurityQuotation quote = _marketDataService.GetSecurityQuotation(portfolioStock.SecurityCode);
                portfolioStock.LastPrice        = quote.LastPrice;
                portfolioStock.StockMarketValue = quote.LastPrice * portfolioStock.AvailableBalance;
                portfolioStock.Greeks           = new PortfolioGreeks(portfolioStock.AdjustedAvailableQuantity,
                                                                      new Greeks()
                {
                    Delta = 1
                }, portfolioStock.OptionSide, 1);
            }

            #endregion

            IEnumerable <BasePortfolioItemGroup> groupedByStrategies = _strategyService.GetPortfolioItemsGroupedByStrategy(portfolioOptions, portfolioStocks);

            List <BasePortfolioItemGroupViewModel> result =
                Mapper.Map <IEnumerable <BasePortfolioItemGroup>, IEnumerable <BasePortfolioItemGroupViewModel> >(groupedByStrategies)
                .ToList();

            return(result);
        }
Example #6
0
        public EntityResponse <OptionChain> GetOptionChain(string underlying)
        {
            EntityResponse <StockQuoteInfo> stockQuote = GetStockQuote(underlying);

            if (!stockQuote.IsSuccess)
            {
                return(EntityResponse <OptionChain> .Error(stockQuote));
            }

            EntityResponse <List <OptionBasicInformation> > optionBasicInformationResponse = _marketDataProvider.GetOptionBasicInformation(underlying);

            if (!optionBasicInformationResponse.IsSuccess)
            {
                return(EntityResponse <OptionChain> .Error(optionBasicInformationResponse));
            }

            double interestRate = _riskFreeRateProvider.GetRiskFreeRate();

            decimal spotPrice = stockQuote.Entity.LastPrice == 0
                ? (stockQuote.Entity.PreviousClose ?? 0)
                : (stockQuote.Entity.LastPrice ?? 0);

            //filtering OptionBasicInformation and get all not expired
            DateTime nowInmarketTimeZone = _marketWorkTimeService.NowInMarketTimeZone.Date;
            List <OptionBasicInformation> optionsBasicInformation = optionBasicInformationResponse.Entity
                                                                    .Where(item => item.ExpireDate.Date >= nowInmarketTimeZone.Date)
                                                                    .ToList();

            List <string> optionNumbers = optionsBasicInformation.Select(item => item.OptionNumber).Distinct().ToList();

            EntityResponse <List <OptionQuotation> > optionQuotesResponse = GetOptionQuotesByOptionNumbers(optionNumbers);

            if (!optionQuotesResponse.IsSuccess)
            {
                return(EntityResponse <OptionChain> .Error(optionQuotesResponse));
            }

            // To filter the optionBasicInformation
            Dictionary <string, OptionQuotation> optionQuotesDict = new Dictionary <string, OptionQuotation>();

            foreach (OptionQuotation itemOptionQuotation in optionQuotesResponse.Entity)
            {
                optionQuotesDict.Add(itemOptionQuotation.OptionNumber, itemOptionQuotation);
            }

            if (!MemoryCache.IsOptionChainCacheExpired(underlying))
            {
                // memory cache working.
                MemoryCache.OptionChainCache[underlying].OptionChains.UpdateQuotation((double)spotPrice, interestRate, optionQuotesResponse.Entity);
                return(MemoryCache.OptionChainCache[underlying].OptionChains);
            }

            // todo: 4 requests here. Big problem with performance

            SecurityInformationCache securityInfo = _marketDataProvider
                                                    .GetAllSecuritiesInformation().FirstOrDefault(s => s.SecurityCode == underlying);

            if (securityInfo == null)
            {
                return(ErrorCode.SZKingdomLibraryNoRecords);
            }

            HashSet <OptionPair> chains = new HashSet <OptionPair>();

            foreach (OptionBasicInformation optionBasicInformation in optionsBasicInformation)
            {
                // Filter the option if the quotation of the specified options cannot be found
                if (!optionQuotesDict.ContainsKey(optionBasicInformation.OptionNumber))
                {
                    continue;
                }

                DateAndNumberOfDaysUntil expiry = _marketWorkTimeService
                                                  .GetNumberOfDaysLeftUntilExpiry(optionBasicInformation.ExpireDate);

                OptionPair pair = new OptionPair
                {
                    Expiry            = expiry,
                    StrikePrice       = (double)optionBasicInformation.StrikePrice,
                    PremiumMultiplier = optionBasicInformation.OptionUnit,
                    SecurityCode      = optionBasicInformation.OptionUnderlyingCode,
                    SecurityName      = optionBasicInformation.OptionUnderlyingName
                };

                if (!chains.Contains(pair))
                {
                    chains.Add(pair);
                }
                else
                {
                    pair = chains.Single(c => c.Equals(pair));
                }

                Option op = new Option(pair, optionBasicInformation.OptionNumber, optionBasicInformation.OptionCode)
                {
                    Name          = optionBasicInformation.OptionName,
                    OptionName    = optionBasicInformation.OptionName,
                    OpenInterest  = optionBasicInformation.UncoveredPositionQuantity,
                    SecurityCode  = optionBasicInformation.OptionUnderlyingCode,
                    PreviousClose = (double)optionBasicInformation.PreviousClosingPrice,
                    Greeks        = new Greeks()
                };
                if (optionBasicInformation.OptionType == OptionType.Call)
                {
                    op.LegType      = LegType.Call;
                    pair.CallOption = op;
                }
                else
                {
                    op.LegType     = LegType.Put;
                    pair.PutOption = op;
                }
            }

            OptionChain chain = new OptionChain(chains, (double)spotPrice, interestRate, optionQuotesResponse.Entity);

            MemoryCache.AddOrUpdateOptionChainCache(underlying, chain);
            return(chain);
        }