internal static bool TryEstimatePrice(double putQty, double callQty, IOptionSeries optSer, IOptionStrikePair pair, InteractiveSeries smile, double f, double timeToExpiry, double riskFreeRate, out double rawPrice) { rawPrice = Double.NaN; if (timeToExpiry < Double.Epsilon) { throw new ArgumentOutOfRangeException("timeToExpiry", "timeToExpiry must be above zero. timeToExpiry:" + timeToExpiry); } double pnl1 = 0; // Флаг того, что ПНЛ по всем инструментам был расчитан верно bool pnlIsCorrect1 = true; { double pairPnl; pnlIsCorrect1 &= SingleSeriesProfile.TryGetPairPrice( putQty, callQty, smile, pair, f, timeToExpiry, riskFreeRate, out pairPnl); pnl1 += pairPnl; } if (pnlIsCorrect1) { //rawPrice = (cash1 + pnl1); // В моих терминах "Цена одного опциона" будет даваться величиной pnl1 rawPrice = pnl1; return(true); } else { return(false); } }
/// <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); } }
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); } }