internal static bool TryEstimateSpeed(PositionsManager posMan, IOptionSeries optSer, IOptionStrikePair[] pairs,
                                              InteractiveSeries smile, NumericalGreekAlgo greekAlgo,
                                              double f, double dF, double timeToExpiry, out double rawSpeed)
        {
            rawSpeed = Double.NaN;

            if (timeToExpiry < Double.Epsilon)
            {
                throw new ArgumentOutOfRangeException("timeToExpiry", "timeToExpiry must be above zero. timeToExpiry:" + timeToExpiry);
            }

            double gamma1, gamma2;
            bool   ok1 = SingleSeriesNumericalGamma.TryEstimateGamma(posMan, optSer, pairs, smile, greekAlgo,
                                                                     f - dF, dF, timeToExpiry, out gamma1);

            if (!ok1)
            {
                return(false);
            }

            bool ok2 = SingleSeriesNumericalGamma.TryEstimateGamma(posMan, optSer, pairs, smile, greekAlgo,
                                                                   f + dF, dF, timeToExpiry, out gamma2);

            if (!ok2)
            {
                return(false);
            }

            rawSpeed = (gamma2 - gamma1) / 2.0 / dF;
            return(true);
        }
        internal static bool TryEstimateGamma(double putQty, double callQty, IOptionSeries optSer, IOptionStrikePair pair,
                                              InteractiveSeries smile, NumericalGreekAlgo greekAlgo,
                                              double f, double dF, double timeToExpiry, double riskFreeRate, out double rawGamma)
        {
            rawGamma = Double.NaN;

            if (timeToExpiry < Double.Epsilon)
            {
                throw new ArgumentOutOfRangeException("timeToExpiry", "timeToExpiry must be above zero. timeToExpiry:" + timeToExpiry);
            }

            double delta1, delta2;
            bool   ok1 = OptionsBoardNumericalDelta.TryEstimateDelta(putQty, callQty, optSer, pair, smile, greekAlgo,
                                                                     f - dF, dF, timeToExpiry, riskFreeRate, out delta1);

            if (!ok1)
            {
                return(false);
            }

            bool ok2 = OptionsBoardNumericalDelta.TryEstimateDelta(putQty, callQty, optSer, pair, smile, greekAlgo,
                                                                   f + dF, dF, timeToExpiry, riskFreeRate, out delta2);

            if (!ok2)
            {
                return(false);
            }

            rawGamma = (delta2 - delta1) / 2.0 / dF;
            return(true);
        }
        /// <summary>
        /// Тета будет иметь размерность 'пункты за год'.
        /// Обычно же опционщики любят смотреть размерность 'пункты за день'.
        /// Поэтому полученное сырое значение ещё надо делить на количество дней в году.
        /// (Эквивалентно умножению на интересующий набег времени для получения дифференциала).
        /// </summary>
        internal static bool TryEstimateTheta(double putQty, double callQty, IOptionSeries optSer, IOptionStrikePair pair,
                                              InteractiveSeries smile, NumericalGreekAlgo greekAlgo,
                                              double f, double timeToExpiry, double tStep, double riskFreeRate, out double rawTheta)
        {
            rawTheta = Double.NaN;

            if (timeToExpiry < Double.Epsilon)
            {
                throw new ArgumentOutOfRangeException("timeToExpiry", "timeToExpiry must be above zero. timeToExpiry:" + timeToExpiry);
            }

            double t1   = (timeToExpiry - tStep > Double.Epsilon) ? (timeToExpiry - tStep) : (0.5 * timeToExpiry);
            double pnl1 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect1 = true;
            {
                // 2. Изменение времени
                // ВАЖНО: нормальный алгоритм сдвига улыбки во времени будет в платной версии "Пакета Каленковича"
                InteractiveSeries actualSmile = SingleSeriesProfile.GetSmileAtTime(smile, NumericalGreekAlgo.FrozenSmile, t1);

                {
                    double pairPnl;
                    pnlIsCorrect1 &= SingleSeriesProfile.TryGetPairPrice(
                        putQty, callQty, actualSmile, pair, f, t1, riskFreeRate, out pairPnl);
                    pnl1 += pairPnl;
                }
            }

            double t2   = timeToExpiry + tStep;
            double pnl2 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect2 = true;

            {
                // ВАЖНО: нормальный алгоритм сдвига улыбки во времени будет в платной версии "Пакета Каленковича"
                InteractiveSeries actualSmile = SingleSeriesProfile.GetSmileAtTime(smile, NumericalGreekAlgo.FrozenSmile, t2);

                {
                    double pairPnl;
                    pnlIsCorrect2 &= SingleSeriesProfile.TryGetPairPrice(
                        putQty, callQty, actualSmile, pair, f, t2, riskFreeRate, out pairPnl);
                    pnl2 += pairPnl;
                }
            }

            if (pnlIsCorrect1 && pnlIsCorrect2)
            {
                //rawTheta = ((cash2 + pnl2) - (cash1 + pnl1)) / (t2 - t1);
                rawTheta = (pnl2 - pnl1) / (t2 - t1);
                // Переворачиваю тету, чтобы жить в календарном времени
                rawTheta = -rawTheta;
                return(true);
            }
            else
            {
                return(false);
            }
        }
        /// <summary>
        /// Вега будет иметь размерность 'пункты за 100% волатильности'.
        /// Обычно же опционщики любят смотреть размерность 'пункты за 1% волатильности'.
        /// Поэтому полученное сырое значение ещё надо делить на 100%.
        /// (Эквивалентно умножению на интересующий набег волы для получения дифференциала).
        /// </summary>
        internal static bool TryEstimateVega(double putQty, double callQty, IOptionSeries optSer, IOptionStrikePair pair,
                                             InteractiveSeries smile, NumericalGreekAlgo greekAlgo,
                                             double f, double dSigma, double timeToExpiry, double riskFreeRate, out double rawVega)
        {
            rawVega = Double.NaN;

            if (timeToExpiry < Double.Epsilon)
            {
                throw new ArgumentOutOfRangeException("timeToExpiry", "timeToExpiry must be above zero. timeToExpiry:" + timeToExpiry);
            }

            SmileInfo sInfo = smile.GetTag <SmileInfo>();

            if (sInfo == null)
            {
                return(false);
            }

            double pnl1 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect1 = true;
            {
                // Для первой точки улыбку не трогаем
                {
                    double pairPnl;
                    pnlIsCorrect1 &= SingleSeriesProfile.TryGetPairPrice(
                        putQty, callQty, smile, pair, f, timeToExpiry, riskFreeRate, out pairPnl);
                    pnl1 += pairPnl;
                }
            }

            double pnl2 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect2 = true;

            {
                //InteractiveSeries actualSmile = SingleSeriesProfile.GetRaisedSmile(smile, greekAlgo, dSigma);
                SmileInfo actualSmile = SingleSeriesProfile.GetRaisedSmile(sInfo, greekAlgo, dSigma);

                double pairPnl;
                pnlIsCorrect2 &= SingleSeriesProfile.TryGetPairPrice(
                    putQty, callQty, actualSmile, pair, f, timeToExpiry, riskFreeRate, out pairPnl);
                pnl2 += pairPnl;
            }

            if (pnlIsCorrect1 && pnlIsCorrect2)
            {
                // Первая точка совпадает с текущей, поэтому нет деления на 2.
                //rawVega = ((cash2 + pnl2) - (cash1 + pnl1)) / dSigma;
                rawVega = (pnl2 - pnl1) / dSigma;
                return(true);
            }
            else
            {
                return(false);
            }
        }
Exemple #5
0
        /// <summary>
        /// Тета будет иметь размерность 'пункты за год'.
        /// Обычно же опционщики любят смотреть размерность 'пункты за день'.
        /// Поэтому полученное сырое значение ещё надо делить на количество дней в году.
        /// (Эквивалентно умножению на интересующий набег времени для получения дифференциала).
        /// </summary>
        internal static bool TryEstimateTheta(PositionsManager posMan, IOptionStrikePair[] pairs,
                                              InteractiveSeries smile, NumericalGreekAlgo greekAlgo,
                                              double f, double timeToExpiry, double tStep, out double rawTheta)
        {
            rawTheta = Double.NaN;

            if (timeToExpiry < Double.Epsilon)
            {
                throw new ArgumentOutOfRangeException("timeToExpiry", "timeToExpiry must be above zero. timeToExpiry:" + timeToExpiry);
            }

            SmileInfo sInfo = smile.GetTag <SmileInfo>();

            if (sInfo == null)
            {
                return(false);
            }

            double t1 = (timeToExpiry - tStep > Double.Epsilon) ? (timeToExpiry - tStep) : (0.5 * timeToExpiry);
            double cash1 = 0, pnl1 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect1 = true;
            {
                // TODO: фьюч на даёт вклад в тету???
                //SingleSeriesProfile.GetBasePnl(posMan, optSer.UnderlyingAsset, optSer.UnderlyingAsset.Bars.Count - 1, f, out cash1, out pnl1);

                //// 1. Изменение положения БА
                //InteractiveSeries actualSmile = SingleSeriesProfile.GetActualSmile(smile, greekAlgo, f);

                SmileInfo actualSmile;
                // 1. Изменение положения БА
                actualSmile = SingleSeriesProfile.GetActualSmile(sInfo, greekAlgo, f);

                // 2. Изменение времени
                // ВАЖНО: нормальный алгоритм сдвига улыбки во времени будет в платной версии "Пакета Каленковича"
                actualSmile = SingleSeriesProfile.GetSmileAtTime(actualSmile, NumericalGreekAlgo.FrozenSmile, t1);

                for (int j = 0; j < pairs.Length; j++)
                {
                    IOptionStrikePair pair = pairs[j];
                    double            pairPnl, pairCash;
                    //double putPx = FinMath.GetOptionPrice(f, pair.Strike, dT, sigma.Value, 0, false);
                    //SingleSeriesProfile.GetPairPnl(posMan, actualSmile, pair, f, t1, out pairCash, out pairPnl);
                    pnlIsCorrect1 &= SingleSeriesProfile.TryGetPairPnl(posMan, actualSmile, pair, f, t1, out pairCash, out pairPnl);
                    cash1         += pairCash;
                    pnl1          += pairPnl;
                }
            }

            double t2 = timeToExpiry + tStep;
            double cash2 = 0, pnl2 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect2 = true;

            {
                // фьюч на даёт вклад в вегу
                //SingleSeriesProfile.GetBasePnl(posMan, optSer.UnderlyingAsset, optSer.UnderlyingAsset.Bars.Count - 1, f, out cash2, out pnl2);

                //// 1. Изменение положения БА
                //InteractiveSeries actualSmile = SingleSeriesProfile.GetActualSmile(smile, greekAlgo, f);

                SmileInfo actualSmile;
                // 1. Изменение положения БА
                actualSmile = SingleSeriesProfile.GetActualSmile(sInfo, greekAlgo, f);

                // 2. Изменение времени
                // ВАЖНО: нормальный алгоритм сдвига улыбки во времени будет в платной версии "Пакета Каленковича"
                actualSmile = SingleSeriesProfile.GetSmileAtTime(actualSmile, NumericalGreekAlgo.FrozenSmile, t2);

                for (int j = 0; j < pairs.Length; j++)
                {
                    IOptionStrikePair pair = pairs[j];
                    double            pairPnl, pairCash;
                    //double putPx = FinMath.GetOptionPrice(f, pair.Strike, dT, sigma.Value, 0, false);
                    //SingleSeriesProfile.GetPairPnl(posMan, actualSmile, pair, f, t2, out pairCash, out pairPnl);
                    pnlIsCorrect2 &= SingleSeriesProfile.TryGetPairPnl(posMan, actualSmile, pair, f, t2, out pairCash, out pairPnl);
                    cash2         += pairCash;
                    pnl2          += pairPnl;
                }
            }

            if (pnlIsCorrect1 && pnlIsCorrect2)
            {
                rawTheta = ((cash2 + pnl2) - (cash1 + pnl1)) / (t2 - t1);
                // Переворачиваю тету, чтобы жить в календарном времени
                rawTheta = -rawTheta;
                return(true);
            }
            else
            {
                return(false);
            }
        }
Exemple #6
0
        internal static bool TryEstimateDelta(double putQty, double callQty, IOptionSeries optSer, IOptionStrikePair pair,
                                              InteractiveSeries smile, NumericalGreekAlgo greekAlgo,
                                              double f, double dF, double timeToExpiry, double riskFreeRate, out double rawDelta)
        {
            rawDelta = Double.NaN;

            if (timeToExpiry < Double.Epsilon)
            {
                throw new ArgumentOutOfRangeException("timeToExpiry", "timeToExpiry must be above zero. timeToExpiry:" + timeToExpiry);
            }

            SmileInfo sInfo = smile.Tag as SmileInfo;

            double pnl1 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect1 = true;
            {
                if (sInfo != null)
                {
                    SmileInfo actualSmile = SingleSeriesProfile.GetActualSmile(sInfo, greekAlgo, f - dF);

                    double pairPnl;
                    pnlIsCorrect1 &= SingleSeriesProfile.TryGetPairPrice(
                        putQty, callQty, actualSmile, pair, f - dF, timeToExpiry, riskFreeRate, out pairPnl);
                    pnl1 += pairPnl;
                }
                else
                {
                    // PROD-5746 -- Убираю использование старого неэффективного кода
                    pnlIsCorrect1 = false;

                    Contract.Assert(pnlIsCorrect1, $"[{nameof(OptionsBoardNumericalDelta)}.{nameof(TryEstimateDelta)}] #1 Каким образом получили неподготовленную улыбку? (sInfo == null)");

                    //InteractiveSeries actualSmile = SingleSeriesProfile.GetActualSmile(smile, greekAlgo, f - dF);

                    //double pairPnl;
                    //pnlIsCorrect1 &= SingleSeriesProfile.TryGetPairPrice(
                    //    putQty, callQty, actualSmile, pair, f - dF, timeToExpiry, riskFreeRate, out pairPnl);
                    //pnl1 += pairPnl;
                }
            }

            double pnl2 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect2 = true;

            {
                if (sInfo != null)
                {
                    SmileInfo actualSmile = SingleSeriesProfile.GetActualSmile(sInfo, greekAlgo, f + dF);

                    double pairPnl;
                    pnlIsCorrect2 &= SingleSeriesProfile.TryGetPairPrice(
                        putQty, callQty, actualSmile, pair, f + dF, timeToExpiry, riskFreeRate, out pairPnl);
                    pnl2 += pairPnl;
                }
                else
                {
                    // PROD-5746 -- Убираю использование старого неэффективного кода
                    pnlIsCorrect2 = false;

                    Contract.Assert(pnlIsCorrect2, $"[{nameof(OptionsBoardNumericalDelta)}.{nameof(TryEstimateDelta)}] #2 Каким образом получили неподготовленную улыбку? (sInfo == null)");

                    //InteractiveSeries actualSmile = SingleSeriesProfile.GetActualSmile(smile, greekAlgo, f + dF);

                    //double pairPnl;
                    //pnlIsCorrect2 &= SingleSeriesProfile.TryGetPairPrice(
                    //    putQty, callQty, actualSmile, pair, f + dF, timeToExpiry, riskFreeRate, out pairPnl);
                    //pnl2 += pairPnl;
                }
            }

            if (pnlIsCorrect1 && pnlIsCorrect2)
            {
                //rawDelta = ((cash2 + pnl2) - (cash1 + pnl1)) / 2.0 / dF;
                rawDelta = (pnl2 - pnl1) / 2.0 / dF;
                return(true);
            }
            else
            {
                return(false);
            }
        }
Exemple #7
0
        /// <summary>
        /// Вомма будет иметь размерность 'пункты за 100% волатильности'.
        /// Обычно же опционщики любят смотреть размерность 'пункты за 1% волатильности'.
        /// Поэтому полученное сырое значение ещё надо делить на 100%.
        /// (Эквивалентно умножению на интересующий набег волы для получения дифференциала).
        /// </summary>
        internal static bool TryEstimateVomma(PositionsManager posMan, IOptionSeries optSer, IOptionStrikePair[] pairs,
                                              InteractiveSeries smile, NumericalGreekAlgo greekAlgo,
                                              double f, double dSigma, double timeToExpiry, out double rawVomma)
        {
            rawVomma = Double.NaN;

            if (timeToExpiry < Double.Epsilon)
            {
                throw new ArgumentOutOfRangeException("timeToExpiry", "timeToExpiry must be above zero. timeToExpiry:" + timeToExpiry);
            }

            SmileInfo sInfo = smile.GetTag <SmileInfo>();

            if (sInfo == null)
            {
                return(false);
            }

            double cash1 = 0, pnl1 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect1 = true;
            {
                // фьюч на даёт вклад в вегу
                //SingleSeriesProfile.GetBasePnl(posMan, optSer.UnderlyingAsset, optSer.UnderlyingAsset.Bars.Count - 1, f, out cash1, out pnl1);

                //InteractiveSeries actualSmile;
                //// 1. Изменение положения БА
                //actualSmile = SingleSeriesProfile.GetActualSmile(smile, greekAlgo, f);

                SmileInfo actualSmile;
                // 1. Изменение положения БА
                actualSmile = SingleSeriesProfile.GetActualSmile(sInfo, greekAlgo, f);

                for (int j = 0; j < pairs.Length; j++)
                {
                    IOptionStrikePair pair = pairs[j];
                    double            pairPnl, pairCash;
                    pnlIsCorrect1 &= SingleSeriesProfile.TryGetPairPnl(posMan, actualSmile, pair, f, timeToExpiry, out pairCash, out pairPnl);
                    cash1         += pairCash;
                    pnl1          += pairPnl;
                }
            }

            double cash2 = 0, pnl2 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect2 = true;
            {
                // фьюч на даёт вклад в вегу
                //SingleSeriesProfile.GetBasePnl(posMan, optSer.UnderlyingAsset, optSer.UnderlyingAsset.Bars.Count - 1, f, out cash2, out pnl2);

                //InteractiveSeries actualSmile;
                //// 1. Изменение положения БА
                //actualSmile = SingleSeriesProfile.GetActualSmile(smile, greekAlgo, f);
                //// 2. Подъём улыбки на dSigma
                //actualSmile = SingleSeriesProfile.GetRaisedSmile(actualSmile, greekAlgo, dSigma);

                SmileInfo actualSmile;
                // 1. Изменение положения БА
                actualSmile = SingleSeriesProfile.GetActualSmile(sInfo, greekAlgo, f);
                // 2. Подъём улыбки на dSigma
                actualSmile = SingleSeriesProfile.GetRaisedSmile(actualSmile, greekAlgo, dSigma);

                for (int j = 0; j < pairs.Length; j++)
                {
                    IOptionStrikePair pair = pairs[j];
                    double            pairPnl, pairCash;
                    pnlIsCorrect2 &= SingleSeriesProfile.TryGetPairPnl(posMan, actualSmile, pair, f, timeToExpiry, out pairCash, out pairPnl);
                    cash2         += pairCash;
                    pnl2          += pairPnl;
                }
            }

            double cash3 = 0, pnl3 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect3 = true;

            {
                // фьюч на даёт вклад в вегу
                //SingleSeriesProfile.GetBasePnl(posMan, optSer.UnderlyingAsset, optSer.UnderlyingAsset.Bars.Count - 1, f, out cash2, out pnl2);

                //InteractiveSeries actualSmile;
                //// 1. Изменение положения БА
                //actualSmile = SingleSeriesProfile.GetActualSmile(smile, greekAlgo, f);
                //// 2. Подъём улыбки на dSigma
                //actualSmile = SingleSeriesProfile.GetRaisedSmile(actualSmile, greekAlgo, dSigma);

                SmileInfo actualSmile;
                // 1. Изменение положения БА
                actualSmile = SingleSeriesProfile.GetActualSmile(sInfo, greekAlgo, f);
                // 2. Подъём улыбки на 2*dSigma
                actualSmile = SingleSeriesProfile.GetRaisedSmile(actualSmile, greekAlgo, 2 * dSigma);

                for (int j = 0; j < pairs.Length; j++)
                {
                    IOptionStrikePair pair = pairs[j];
                    double            pairPnl, pairCash;
                    pnlIsCorrect2 &= SingleSeriesProfile.TryGetPairPnl(posMan, actualSmile, pair, f, timeToExpiry, out pairCash, out pairPnl);
                    cash3         += pairCash;
                    pnl3          += pairPnl;
                }
            }

            if (pnlIsCorrect1 && pnlIsCorrect2 && pnlIsCorrect3)
            {
                // См. Вики случай r=2, N=2: https://ru.wikipedia.org/wiki/Численное_дифференцирование
                // f''(x0) ~= (f0 - 2*f1 + f2)/h/h
                rawVomma = ((cash1 + pnl1) - 2 * (cash2 + pnl2) + (cash3 + pnl3)) / dSigma / dSigma;
                return(true);
            }
            else
            {
                return(false);
            }
        }
Exemple #8
0
        /// <summary>
        /// Вега будет иметь размерность 'пункты за 100% волатильности'.
        /// Обычно же опционщики любят смотреть размерность 'пункты за 1% волатильности'.
        /// Поэтому полученное сырое значение ещё надо делить на 100%.
        /// (Эквивалентно умножению на интересующий набег волы для получения дифференциала).
        /// </summary>
        internal static bool TryEstimateVega(PositionsManager posMan, IOptionSeries optSer, IOptionStrikePair[] pairs,
                                             InteractiveSeries smile, NumericalGreekAlgo greekAlgo,
                                             double f, double dSigma, double timeToExpiry, out double rawVega)
        {
            rawVega = Double.NaN;

            if (timeToExpiry < Double.Epsilon)
            {
                throw new ArgumentOutOfRangeException("timeToExpiry", "timeToExpiry must be above zero. timeToExpiry:" + timeToExpiry);
            }

            SmileInfo sInfo = smile.GetTag <SmileInfo>();

            if (sInfo == null)
            {
                return(false);
            }

            double cash1 = 0, pnl1 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect1 = true;
            {
                // фьюч на даёт вклад в вегу
                //SingleSeriesProfile.GetBasePnl(posMan, optSer.UnderlyingAsset, optSer.UnderlyingAsset.Bars.Count - 1, f, out cash1, out pnl1);

                //InteractiveSeries actualSmile;
                //// 1. Изменение положения БА
                //actualSmile = SingleSeriesProfile.GetActualSmile(smile, greekAlgo, f);

                SmileInfo actualSmile;
                // 1. Изменение положения БА
                actualSmile = SingleSeriesProfile.GetActualSmile(sInfo, greekAlgo, f);

                for (int j = 0; j < pairs.Length; j++)
                {
                    IOptionStrikePair pair = pairs[j];
                    double            pairPnl, pairCash;
                    //double putPx = FinMath.GetOptionPrice(f, pair.Strike, dT, sigma.Value, 0, false);
                    //SingleSeriesProfile.GetPairPnl(posMan, actualSmile, pair, f, timeToExpiry, out pairCash, out pairPnl);
                    pnlIsCorrect1 &= SingleSeriesProfile.TryGetPairPnl(posMan, actualSmile, pair, f, timeToExpiry, out pairCash, out pairPnl);
                    cash1         += pairCash;
                    pnl1          += pairPnl;
                }
            }

            double cash2 = 0, pnl2 = 0;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect2 = true;

            {
                // фьюч на даёт вклад в вегу
                //SingleSeriesProfile.GetBasePnl(posMan, optSer.UnderlyingAsset, optSer.UnderlyingAsset.Bars.Count - 1, f, out cash2, out pnl2);

                //InteractiveSeries actualSmile;
                //// 1. Изменение положения БА
                //actualSmile = SingleSeriesProfile.GetActualSmile(smile, greekAlgo, f);
                //// 2. Подъём улыбки на dSigma
                //actualSmile = SingleSeriesProfile.GetRaisedSmile(actualSmile, greekAlgo, dSigma);

                SmileInfo actualSmile;
                // 1. Изменение положения БА
                actualSmile = SingleSeriesProfile.GetActualSmile(sInfo, greekAlgo, f);
                // 2. Подъём улыбки на dSigma
                actualSmile = SingleSeriesProfile.GetRaisedSmile(actualSmile, greekAlgo, dSigma);

                for (int j = 0; j < pairs.Length; j++)
                {
                    IOptionStrikePair pair = pairs[j];
                    double            pairPnl, pairCash;
                    //double putPx = FinMath.GetOptionPrice(f, pair.Strike, dT, sigma.Value, 0, false);
                    //SingleSeriesProfile.GetPairPnl(posMan, actualSmile, pair, f, timeToExpiry, out pairCash, out pairPnl);
                    pnlIsCorrect2 &= SingleSeriesProfile.TryGetPairPnl(posMan, actualSmile, pair, f, timeToExpiry, out pairCash, out pairPnl);
                    cash2         += pairCash;
                    pnl2          += pairPnl;
                }
            }

            if (pnlIsCorrect1 && pnlIsCorrect2)
            {
                // Первая точка совпадает с текущей, поэтому нет деления на 2.
                rawVega = ((cash2 + pnl2) - (cash1 + pnl1)) / dSigma;
                return(true);
            }
            else
            {
                return(false);
            }
        }
        internal static bool TryEstimateDelta(PositionsManager posMan, IOptionSeries optSer, IOptionStrikePair[] pairs,
                                              InteractiveSeries smile, NumericalGreekAlgo greekAlgo,
                                              double f, double dF, double timeToExpiry, out double rawDelta)
        {
            rawDelta = Double.NaN;

            if (timeToExpiry < Double.Epsilon)
            {
                throw new ArgumentOutOfRangeException("timeToExpiry", "timeToExpiry must be above zero. timeToExpiry:" + timeToExpiry);
            }

            SmileInfo sInfo = smile.GetTag <SmileInfo>();

            if (sInfo == null)
            {
                Contract.Assert(false, $"[{nameof(SingleSeriesNumericalDelta)}.{nameof(TryEstimateDelta)}] #1 Каким образом получили неподготовленную улыбку? (sInfo == null)");

                return(false);
            }

            double cash1, pnl1;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect1 = true;
            {
                SingleSeriesProfile.GetBasePnl(posMan, optSer.UnderlyingAsset, optSer.UnderlyingAsset.Bars.Count - 1, f - dF, out cash1, out pnl1);

                // PROD-5746 -- Убираю использование старого неэффективного кода
                //InteractiveSeries actualSmile = SingleSeriesProfile.GetActualSmile(smile, greekAlgo, f - dF);
                SmileInfo actualSmile = SingleSeriesProfile.GetActualSmile(sInfo, greekAlgo, f - dF);

                for (int j = 0; j < pairs.Length; j++)
                {
                    IOptionStrikePair pair = pairs[j];
                    double            pairPnl, pairCash;
                    //double putPx = FinMath.GetOptionPrice(f, pair.Strike, dT, sigma.Value, 0, false);
                    //SingleSeriesProfile.GetPairPnl(posMan, actualSmile, pair, f - dF, timeToExpiry, out pairCash, out pairPnl);
                    pnlIsCorrect1 &= SingleSeriesProfile.TryGetPairPnl(posMan, actualSmile, pair, f - dF, timeToExpiry, out pairCash, out pairPnl);
                    cash1         += pairCash;
                    pnl1          += pairPnl;
                }
            }

            double cash2, pnl2;
            // Флаг того, что ПНЛ по всем инструментам был расчитан верно
            bool pnlIsCorrect2 = true;

            {
                SingleSeriesProfile.GetBasePnl(posMan, optSer.UnderlyingAsset, optSer.UnderlyingAsset.Bars.Count - 1, f + dF, out cash2, out pnl2);

                // PROD-5746 -- Убираю использование старого неэффективного кода
                //InteractiveSeries actualSmile = SingleSeriesProfile.GetActualSmile(smile, greekAlgo, f + dF);
                SmileInfo actualSmile = SingleSeriesProfile.GetActualSmile(sInfo, greekAlgo, f + dF);

                for (int j = 0; j < pairs.Length; j++)
                {
                    IOptionStrikePair pair = pairs[j];
                    double            pairPnl, pairCash;
                    //double putPx = FinMath.GetOptionPrice(f, pair.Strike, dT, sigma.Value, 0, false);
                    //SingleSeriesProfile.GetPairPnl(posMan, actualSmile, pair, f + dF, timeToExpiry, out pairCash, out pairPnl);
                    pnlIsCorrect2 &= SingleSeriesProfile.TryGetPairPnl(posMan, actualSmile, pair, f + dF, timeToExpiry, out pairCash, out pairPnl);
                    cash2         += pairCash;
                    pnl2          += pairPnl;
                }
            }

            if (pnlIsCorrect1 && pnlIsCorrect2)
            {
                rawDelta = ((cash2 + pnl2) - (cash1 + pnl1)) / 2.0 / dF;
                return(true);
            }
            else
            {
                return(false);
            }
        }