Пример #1
0
        /// <summary>
        /// Вычисление нескольких видов наклона улыбки и обновление исторической серии,
        /// которая потенциально может быть сохранена в глобальный кеш.
        /// При записи в кеш серия помещается в NotClearableContainer, чтобы выживать при очистке памяти.
        /// </summary>
        public static bool TryCalcAndWriteSkews(IContext context, NotAKnotCubicSpline smileSpline,
                                                bool useGlobal, bool allowGlobalWrite, int savePeriod,
                                                string futSymbol, DateTime optExpiry, double futPx, DateTime lastBarDate,
                                                TimeRemainMode tRemainMode, double plainTimeAsYears, double timeAsYears)
        {
            bool successSkew = false;
            var  splineD1    = smileSpline.DeriveD1();

            if (splineD1.TryGetValue(futPx, out var skewAtm))
            {
                //string symbol = optSer.UnderlyingAsset.Symbol;
                // А. Записываем в Глобальный Кеш РАЗМЕРНЫЙ наклон (модель времени неважна)
                {
                    string skewKey = IvOnF.GetSkewCashKey(futSymbol, optExpiry, SmileSkewMode.RawSkew, TimeRemainMode.PlainCalendar);
                    var    ivSkews = LoadOrCreateHistoryDict(context, useGlobal, skewKey);
                    // Это просто запись на диск. К успешности вычисления наклона successSkew отношения не имеет
                    successSkew = TryWrite(context, useGlobal, allowGlobalWrite,
                                           savePeriod, skewKey, ivSkews, lastBarDate, skewAtm);
                }

                // В. Записываем в Глобальный Кеш БЕЗРАЗМЕРНЫЙ наклон В БИРЖЕВОМ ВРЕМЕНИ (PlainCalendar)
                {
                    double dSigmaDxExchange = SmileImitation5.GetDSigmaDx(futPx, plainTimeAsYears, skewAtm, 0);
                    if (!DoubleUtil.IsNaN(dSigmaDxExchange))
                    {
                        string skewKey = IvOnF.GetSkewCashKey(futSymbol, optExpiry, SmileSkewMode.ExchangeSkew, TimeRemainMode.PlainCalendar);
                        var    ivSkews = LoadOrCreateHistoryDict(context, useGlobal, skewKey);
                        // Это просто запись на диск. К успешности вычисления наклона successSkew отношения не имеет
                        successSkew = TryWrite(context, useGlobal, allowGlobalWrite,
                                               savePeriod, skewKey, ivSkews, lastBarDate, dSigmaDxExchange);
                    }
                }

                // Д. Записываем в Глобальный Кеш БЕЗРАЗМЕРНЫЙ наклон В НАШЕМ ВРЕМЕНИ (в соответствии с tRemainMode)
                {
                    double dSigmaDxRescaled = SmileImitation5.GetDSigmaDx(futPx, timeAsYears, skewAtm, 0);
                    if (!DoubleUtil.IsNaN(dSigmaDxRescaled))
                    {
                        string skewKey = IvOnF.GetSkewCashKey(futSymbol, optExpiry, SmileSkewMode.RescaledSkew, tRemainMode);
                        var    ivSkews = LoadOrCreateHistoryDict(context, useGlobal, skewKey);
                        // Это просто запись на диск. К успешности вычисления наклона successSkew отношения не имеет
                        successSkew = TryWrite(context, useGlobal, allowGlobalWrite,
                                               savePeriod, skewKey, ivSkews, lastBarDate, dSigmaDxRescaled);
                    }
                }
            } // End if (splineD1.TryGetValue(futPx, out var skewAtm))

            return(successSkew);
        }
Пример #2
0
        /// <summary>
        /// Метод под флаг TemplateTypes.SECURITY, чтобы подключаться к источнику-БА
        /// </summary>
        public IList <double> Execute(ISecurity sec)
        {
            if (sec == null)
            {
                return(Constants.EmptyListDouble);
            }

            Dictionary <DateTime, double> hvSigmas;

            #region Get cache
            int    barLengthInSeconds = (int)sec.IntervalInstance.ToSeconds();
            string cashKey            = GetGlobalCashKey(sec.Symbol, false, m_useAllData, barLengthInSeconds, m_annualizingMultiplier, m_period);
            if (UseGlobalCache)
            {
                object globalObj = Context.LoadGlobalObject(cashKey, true);
                hvSigmas = globalObj as Dictionary <DateTime, double>;
                // PROD-3970 - 'Важный' объект
                if (hvSigmas == null)
                {
                    var container = globalObj as NotClearableContainer;
                    if ((container != null) && (container.Content != null))
                    {
                        hvSigmas = container.Content as Dictionary <DateTime, double>;
                    }
                }
                if (hvSigmas == null)
                {
                    hvSigmas = new Dictionary <DateTime, double>();
                    var container = new NotClearableContainer(hvSigmas);
                    Context.StoreGlobalObject(cashKey, container, true);
                }
            }
            else
            {
                object locObj = Context.LoadObject(cashKey);
                hvSigmas = locObj as Dictionary <DateTime, double>;
                // PROD-3970 - 'Важный' объект
                if (hvSigmas == null)
                {
                    var container = locObj as NotClearableContainer;
                    if ((container != null) && (container.Content != null))
                    {
                        hvSigmas = container.Content as Dictionary <DateTime, double>;
                    }
                }
                if (hvSigmas == null)
                {
                    hvSigmas = new Dictionary <DateTime, double>();
                    var container = new NotClearableContainer(hvSigmas);
                    Context.StoreObject(cashKey, container);
                }
            }
            #endregion Get cache

            List <double> historySigmas = LocalHistory;

            if (m_reset || m_context.Runtime.IsFixedBarsCount)
            {
                historySigmas.Clear();
            }

            int len = Context.BarsCount;
            // Локальный ключ можно всегда формировать вместе с периодом!
            string logsLocObjKey = VariableId + "_logs_" + m_period;
            object logsLocObj    = m_context.LoadObject(logsLocObjKey);
            LinkedList <KeyValuePair <DateTime, double> > logs = logsLocObj as LinkedList <KeyValuePair <DateTime, double> >;
            #region Get cache
            // PROD-3970 - 'Важный' объект
            if (logs == null)
            {
                var container = logsLocObj as NotClearableContainer;
                if ((container != null) && (container.Content != null))
                {
                    logs = container.Content as LinkedList <KeyValuePair <DateTime, double> >;
                }
            }
            if (logs == null)
            {
                logs = new LinkedList <KeyValuePair <DateTime, double> >();
                var container = new NotClearableContainer(logs);
                m_context.StoreObject(logsLocObjKey, container);
            }
            #endregion Get cache

            if (m_reset || m_context.Runtime.IsFixedBarsCount)
            {
                logs.Clear();
            }

            if (len <= 0)
            {
                return(historySigmas);
            }

            // Типа, кеширование?
            for (int j = historySigmas.Count; j < len; j++)
            {
                IDataBar bar;
                try
                {
                    // Наблюдал на реале странную картину (ВО ВРЕМЯ КЛИРИНГА!):
                    // Context.BarsCount == 3843 && sec.Bars.Count == 3842
                    bar = sec.Bars[j];
                    // если бар технический (то есть имеет нулевой объём), пропускаем его
                    // 2017-04-26 - На эксанте при запросе истории все бары имеют нулевой объём, но при этом большинство из них являются нормальными:
                    //              имеют ненулевой размах и осмысленные значения открытия/закрытия
                    if ((bar.Volume <= Double.Epsilon) && (DoubleUtil.AreClose(bar.High, bar.Low)))
                    {
                        // пишу NaN в такой ситуации
                        historySigmas.Add(Constants.NaN);
                        continue;
                    }
                }
                catch (ArgumentOutOfRangeException)
                {
                    // Перехватываю aorEx и пишу NaN в такой ситуации
                    historySigmas.Add(Constants.NaN);
                    continue;
                }

                DateTime t  = bar.Date;
                double   v  = bar.Close;
                double   ln = Math.Log(v);

                Contract.Assert(logs != null, "Каким образом переменная logs оказалась null?");
                logs.AddLast(new KeyValuePair <DateTime, double>(t, ln));

                double hv;
                if (TryEstimateHv(
                        logs, m_period, barLengthInSeconds, m_annualizingMultiplier,
                        m_useAllData, out hv))
                {
                    double vol = hv;
                    historySigmas.Add(vol);

                    lock (hvSigmas)
                    {
                        hvSigmas[t] = vol;
                    }
                }
                else
                {
                    historySigmas.Add(Constants.NaN);
                }
            }

            // Попытку записи в глобальный кеш делаю только в самом конце всех вычислений
            // для экономии времени на сериализацию и запись
            lock (hvSigmas)
            {
                if (sec.Bars.Count > len - 1)
                {
                    // Наблюдал на реале странную картину (ВО ВРЕМЯ КЛИРИНГА!):
                    // Context.BarsCount == 3760 && sec.Bars.Count == 3759
                    bool success = IvOnF.TryWrite(m_context, UseGlobalCache, AllowGlobalReadWrite, GlobalSavePeriod,
                                                  cashKey, hvSigmas, sec.Bars[len - 1].Date, historySigmas[historySigmas.Count - 1]);
                }

                return(new ReadOnlyCollection <double>(historySigmas));
            }
        }
Пример #3
0
        private IList <double> PrepareData(ISecurity sec, string expiryDate)
        {
            DateTime expiry;

            if ((!DateTime.TryParseExact(expiryDate, IvOnF.DateFormat, CultureInfo.InvariantCulture,
                                         DateTimeStyles.AssumeLocal, out expiry)) &&
                (!DateTime.TryParseExact(expiryDate, IvOnF.DateFormat + " HH:mm", CultureInfo.InvariantCulture,
                                         DateTimeStyles.AssumeLocal, out expiry)))
            {
                string msg = String.Format("[{0}.{1}.PrepareData] Unable to parse expiration date '{2}'. Expected date format '{3}'.",
                                           Context.Runtime.TradeName, GetType().Name, expiryDate, IvOnF.DateFormat);
                m_context.Log(msg, MessageType.Warning, true);
                return(Constants.EmptyListDouble);
            }

            //// и тут я понял, что дату экспирации в любом случае надо задавать руками...
            //string cashKey = typeof(IvOnF).Name + "_ivExchangeSigmas_" + sec.Symbol + "_" +
            //    expiryDate.Replace(':', '-');
            string cashKey = IvOnF.GetCashKey(sec.Symbol, expiry, m_rescaleTime, m_tRemainMode);
            Dictionary <DateTime, double> ivSigmas = null;

            try
            {
                object globalObj = Context.LoadGlobalObject(cashKey, true);
                ivSigmas = globalObj as Dictionary <DateTime, double>;
                // PROD-3970 - 'Важный' объект
                if (ivSigmas == null)
                {
                    var container = globalObj as NotClearableContainer;
                    if ((container != null) && (container.Content != null))
                    {
                        ivSigmas = container.Content as Dictionary <DateTime, double>;
                    }
                }
            }
            catch (NotSupportedException nse)
            {
                string fName = "", path = "";
                if (nse.Data["fName"] != null)
                {
                    fName = nse.Data["fName"].ToString();
                }
                if (nse.Data["path"] != null)
                {
                    path = nse.Data["path"].ToString();
                }
                string msg = String.Format("[{0}.PrepareData] {1} when loading 'ivSigmas' from global cache. cashKey: {2}; Message: {3}\r\n\r\nfName: {4}; path: {5}\r\n\r\n{6}",
                                           GetType().Name, nse.GetType().FullName, cashKey, nse.Message, fName, path, nse);
                m_context.Log(msg, MessageType.Warning, true);
            }
            catch (Exception ex)
            {
                string msg = String.Format("[{0}.PrepareData] {1} when loading 'ivSigmas' from global cache. cashKey: {2}; Message: {3}\r\n\r\n{4}",
                                           GetType().Name, ex.GetType().FullName, cashKey, ex.Message, ex);
                m_context.Log(msg, MessageType.Warning, true);
            }

            if (ivSigmas == null)
            {
                // Данного ключа в глобальном кеше нет? Тогда выход.
                // [{0}.PrepareData] There is no IV in global cache. Probably, you have to start agent 'Collect IV (ALL)' for security '{1}'.
                string msg = RM.GetStringFormat("OptHandlerMsg.GlobalIvOnF.CacheNotFound", GetType().Name, expiryDate, sec);
                if (m_context.Runtime.IsAgentMode && (!m_ignoreCacheError))
                {
                    throw new ScriptException(msg); // PROD-4624 - Андрей велит кидать исключение.
                }
                bool isExpired = true;
                if (m_context.Runtime.IsAgentMode)
                {
                    int      amount = sec.Bars.Count;
                    DateTime today  = (amount > 0) ? sec.Bars[amount - 1].Date : new DateTime();
                    isExpired = expiry.Date.AddDays(1) < today.Date;
                }
                // А если в режиме лаборатории, тогда только жалуемся и продолжаем.
                m_context.Log(msg, MessageType.Warning, !isExpired); // Если серия уже умерла, пишем только в локальный лог
                return(Constants.EmptyListDouble);
            }

            List <double> res = new List <double>();

            int len = sec.Bars.Count;

            if (len <= 0)
            {
                return(res);
            }

            int    oldResLen = res.Count;
            double prevIv    = Double.NaN;

            for (int j = oldResLen; j < len; j++)
            {
                DateTime now = sec.Bars[j].Date;
                double   iv;
                if (ivSigmas.TryGetValue(now, out iv) && (!Double.IsNaN(iv)) && (iv > 0))
                {
                    prevIv = iv;
                    res.Add(iv);
                }
                else
                {
                    if (m_repeatLastIv)
                    {
                        if (!Double.IsNaN(prevIv))
                        {
                            iv = prevIv;
                        }
                        else
                        {
                            iv = Constants.NaN;
                            if (j == 0)
                            {
                                #region Отдельно обрабатываю нулевой бар
                                double   tmp      = Double.NaN;
                                DateTime foundKey = new DateTime(1, 1, 1);
                                // [2016-01-19] Когда история становится слишком длинной, это может вызывать проблемы
                                // при итерировании в foreach. Потому что другой поток может в этот момент добавить новую точку в коллекцию.
                                int repeat = 7;
                                while (repeat > 0)
                                {
                                    tmp      = Double.NaN;
                                    foundKey = new DateTime(1, 1, 1);
                                    try
                                    {
                                        lock (ivSigmas)
                                        {
                                            foreach (var kvp in ivSigmas)
                                            {
                                                if (kvp.Key > now)
                                                {
                                                    continue;
                                                }

                                                if (foundKey < kvp.Key)
                                                {
                                                    foundKey = kvp.Key;
                                                    tmp      = kvp.Value;
                                                }
                                            }
                                        }
                                        repeat = -100;
                                    }
                                    catch (InvalidOperationException invOpEx)
                                    {
                                        repeat--;
                                        Thread.Sleep(10);
                                        if (repeat <= 0)
                                        {
                                            string msg = String.Format("[{0}.PrepareData] {1} when iterate through 'ivSigmas'. cashKey: {2}; Message: {3}\r\n\r\n{4}",
                                                                       GetType().Name, invOpEx.GetType().FullName, cashKey, invOpEx.Message, invOpEx);
                                            m_context.Log(msg, MessageType.Warning, true);
                                            throw;
                                        }
                                    }
                                }

                                if ((foundKey.Year > 1) && (!Double.IsNaN(tmp)) && (tmp > 0))
                                {
                                    iv     = tmp;
                                    prevIv = iv;
                                }
                                #endregion Отдельно обрабатываю нулевой бар
                            }
                        }
                        res.Add(iv);
                    }
                    else
                    {
                        res.Add(Constants.NaN);
                    }
                }
            }

            return(res);
        }
Пример #4
0
        /// <summary>
        /// Обработчик под тип входных данных OPTION_SERIES
        /// </summary>
        public IList <double> Execute(IOptionSeries optSer)
        {
            if (optSer == null)
            {
                string msg = "[IV ATM] (optSer == null)";
                m_context.Log(msg, MessageType.Warning, false);

                return(Constants.EmptyListDouble);
            }

            Dictionary <DateTime, double> ivSigmas;

            #region Get cache
            DateTime expiry  = optSer.ExpirationDate.Date;
            string   cashKey = IvOnF.GetCashKey(optSer.UnderlyingAsset.Symbol, expiry, m_rescaleTime, m_tRemainMode);
            ivSigmas = LoadOrCreateHistoryDict(UseGlobalCache, cashKey);
            #endregion Get cache

            List <double> res;
            ISecurity     sec = optSer.UnderlyingAsset;
            int           len = sec.Bars.Count;
            if (len <= 0)
            {
                return(Constants.EmptyListDouble);
            }

            if (m_context.IsFixedBarsCount)
            {
                #region Ветка с ФИКСИРОВАННЫМ количеством баров
                double lastIv = Double.NaN;
                res = new List <double>(len);
                for (int j = 0; j < len; j++)
                {
                    DateTime now = sec.Bars[j].Date;
                    double   iv;
                    if ((ivSigmas.TryGetValue(now, out iv)) && (!Double.IsNaN(iv)) && (iv > 0))
                    {
                        lastIv = iv;
                        res.Add(iv);
                    }
                    else
                    {
                        if (m_repeatLastIv && (!Double.IsNaN(lastIv)))
                        {
                            res.Add(lastIv);
                        }
                        else
                        {
                            res.Add(Constants.NaN);
                        }
                    }
                }
                #endregion Ветка с ФИКСИРОВАННЫМ количеством баров
            }
            else
            {
                #region Ветка с нарастающим количеством баров
                res = LocalHistory;
                // PROD-1933
                // 1. Выполняю очистку локального кеша в сценарии восстановления соединения после дисконнекта
                if (res.Count > len)
                {
                    res.Clear();
                }

                // 2. Ищу последнее валидное значение в кеше причем только если это может быть нужно
                double lastIv = Double.NaN;
                if (m_repeatLastIv)
                {
                    for (int j = res.Count - 1; j >= 0; j--)
                    {
                        if ((!Double.IsNaN(res[j])) && (res[j] > 0))
                        {
                            lastIv = res[j];
                            break;
                        }
                    }
                }

                for (int j = res.Count; j < len; j++)
                {
                    DateTime now = sec.Bars[j].Date;
                    double   iv;
                    if ((ivSigmas.TryGetValue(now, out iv)) && (!Double.IsNaN(iv)) && (iv > 0))
                    {
                        lastIv = iv;
                        res.Add(iv);
                    }
                    else
                    {
                        if (m_repeatLastIv && (!Double.IsNaN(lastIv)))
                        {
                            res.Add(lastIv);
                        }
                        else
                        {
                            res.Add(Constants.NaN);
                        }
                    }
                }
                #endregion Ветка с нарастающим количеством баров
            }

            Debug.Assert(res != null, "How is it possible (res == null)?");
            Debug.Assert(res.Count == len, String.Format("Wrong res.Count. res.Count:{0}; expected len:{1}; IsFixedBarsCount:{2}",
                                                         res.Count, len, m_context.IsFixedBarsCount));

            FinInfo baseFinInfo = optSer.UnderlyingAsset.FinInfo;
            // Эта проверка намекает на проблемы с маркет-датой.
            if (baseFinInfo.LastPrice == null)
            {
                string msg = "[IV ATM] (baseFinInfo.LastPrice == null)";
                m_context.Log(msg, MessageType.Warning, false);
                return(res);
            }

            try
            {
                double sigma;
                double futPx = baseFinInfo.LastPrice.Value;
                NotAKnotCubicSpline spline = PrepareExchangeSmileSpline(optSer, Double.MinValue, Double.MaxValue);
                if ((spline != null) && spline.TryGetValue(futPx, out sigma) && DoubleUtil.IsPositive(sigma))
                {
                    DateTime lastBarDate = sec.Bars[len - 1].Date;
                    if (m_rescaleTime)
                    {
                        #region Зверская ветка по замене времени
                        double   ivAtm   = sigma;
                        DateTime expDate = optSer.ExpirationDate.Date + m_expiryTime;
                        DateTime now     = baseFinInfo.LastUpdate;

                        // 1. Надо перевести волатильность в абсолютную цену
                        // с учетом плоского календарного времени применяемого РТС
                        double plainTimeAsYears;
                        {
                            double plainTimeAsDays;
                            TimeToExpiry.GetDt(expDate, now, TimeRemainMode.PlainCalendar, false, out plainTimeAsDays,
                                               out plainTimeAsYears);
                        }

                        // 2. Вычисляем 'нормальное' время
                        double timeAsDays, timeAsYears;
                        TimeToExpiry.GetDt(expDate, now, m_tRemainMode, false, out timeAsDays, out timeAsYears);
                        sigma = FinMath.RescaleIvToAnotherTime(plainTimeAsYears, ivAtm, timeAsYears);
                        if (DoubleUtil.IsPositive(sigma))
                        {
                            // Это просто запись на диск. К успешности вычисления волы success отношения не имеет
                            bool success = TryWrite(m_context, UseGlobalCache, AllowGlobalReadWrite,
                                                    GlobalSavePeriod, cashKey, ivSigmas, lastBarDate, sigma);

                            // Теперь надо вычислить безразмерный наклон кодом в классе SmileImitation5
                            bool successSkew = TryCalcAndWriteSkews(m_context, spline, UseGlobalCache, AllowGlobalReadWrite, GlobalSavePeriod,
                                                                    optSer.UnderlyingAsset.Symbol, expiry, futPx, lastBarDate, m_tRemainMode, plainTimeAsYears, timeAsYears);
                        }
                        else
                        {
                            // Если перемасштабировать улыбку не получается придется эту точку проигнорировать
                            // Надо ли сделать соответствующую запись в логе???
                            sigma = Constants.NaN;
                        }
                        #endregion Зверская ветка по замене времени
                    }
                    else
                    {
                        // Это просто запись на диск. К успешности вычисления волы success отношения не имеет
                        bool success = TryWrite(m_context, UseGlobalCache, AllowGlobalReadWrite,
                                                GlobalSavePeriod, cashKey, ivSigmas, lastBarDate, sigma);
                    }
                }
                else
                {
                    sigma = Constants.NaN;
                }

                res[len - 1] = sigma;
            }
            catch (Exception ex)
            {
                m_context.Log(ex.ToString(), MessageType.Error, false);
                return(res);
            }

            if (m_repeatLastIv)
            {
                if (DoubleUtil.AreClose(res[len - 1], Constants.NaN) || Double.IsNaN(res[len - 1]) || (res[len - 1] <= 0))
                {
                    // Итерируюсь с конца в начало пока не найду последний ненулевой элемент.
                    // Использую его в качестве ВСЕХ последних значений ряда.
                    for (int j = len - 1; j >= 0; j--)
                    {
                        if ((!DoubleUtil.AreClose(res[j], Constants.NaN)) && (!Double.IsNaN(res[j])) && (res[j] > 0))
                        {
                            double lastIv = res[j];
                            for (int k = j + 1; k < len; k++)
                            {
                                res[k] = lastIv;
                            }
                            break;
                        }
                    }
                }
            }

            return(new ReadOnlyCollection <double>(res));
        }
Пример #5
0
        public void Execute(double price, double time, IOptionSeries optSer, ICanvasPane pane, int barNum)
        {
            int barsCount = ContextBarsCount;

            if ((barNum < barsCount - 1) || (optSer == null))
            {
                return;
            }

            // PROD-3577
            pane.FeetToBorder2ByDefault = true;

            double futPx = price;
            double dT    = time;

            if (!DoubleUtil.IsPositive(futPx))
            {
                return;
            }
            if (!DoubleUtil.IsPositive(dT))
            {
                return;
            }

            double    sigma;
            IFunction smileFunc = IvOnF.PrepareExchangeSmileSpline(optSer, Double.MinValue, Double.MaxValue);

            if ((smileFunc == null) || (!smileFunc.TryGetValue(futPx, out sigma)) ||
                (!DoubleUtil.IsPositive(sigma)))
            {
                //При работе с Эксанте и прочим Западом Биржевой улыбки не будет
                //Поэтому надо иметь 'План Б': подставить фиксированную волатильность 30%!
                sigma = DefaultSigma;

                // PROD-5968 - У биткойна совсем другой типичный уровень волатильности
                var parent      = optSer.UnderlyingAsset;
                var secDesc     = parent.SecurityDescription;
                var tp          = secDesc.TradePlace;
                var dsClassName = tp?.DataSource?.GetType().Name;
                if (dsClassName == "DeribitDS")
                {
                    sigma = DefaultSigmaDeribit;
                }
                else if (dsClassName == "ExanteDataSource")
                {
                    if (tp.Id == "CME")
                    {
                        if (secDesc.ActiveType.IsFuture() && parent.Symbol.StartsWith("ES"))
                        {
                            sigma = DefaultSigmaEs;
                        }
                    }
                }
            }

            if (pane != null)
            {
                string expiryStr = optSer.ExpirationDate.ToString(TimeToExpiry.DateTimeFormat, CultureInfo.InvariantCulture);
                Rect   rect      = PrepareVieportSettings(expiryStr, futPx, dT, sigma);
                ApplySettings(pane, rect);

                if (ManageXGridStep)
                {
                    var pairs = optSer.GetStrikePairs().ToArray();
                    int pLen  = pairs.Length;
                    if (pLen > 1)
                    {
                        double dK = pairs[1].Strike - pairs[0].Strike;
                        if (pLen > 2)
                        {
                            int t = pLen / 2; // Делим нацело. Для pLen==3 получаем 1
                            dK = pairs[t + 1].Strike - pairs[t].Strike;
                        }

                        pane.XAxisStep    = GetXAxisStep(dK);
                        pane.XAxisDiviser = GetXAxisDivisor(dK);
                    }
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Обработчик под тип входных данных OPTION_SERIES
        /// </summary>
        public double Execute(IOptionSeries optSer, int barNum)
        {
            double failRes = Constants.NaN;

            if (m_repeatLastIv)
            {
                failRes = Double.IsNaN(m_prevIv) ? Constants.NaN : m_prevIv;
            }

            Dictionary <DateTime, double> ivSigmas;

            #region Get cache
            DateTime expiry  = optSer.ExpirationDate.Date;
            string   cashKey = IvOnF.GetCashKey(optSer.UnderlyingAsset.Symbol, expiry, m_rescaleTime, m_tRemainMode);
            ivSigmas = LoadOrCreateHistoryDict(UseGlobalCache, cashKey);
            #endregion Get cache

            ISecurity sec = optSer.UnderlyingAsset;
            int       len = sec.Bars.Count;
            if (len <= 0)
            {
                return(failRes);
            }

            DateTime lastBarDate = sec.Bars[barNum].Date;
            double   iv;
            if ((ivSigmas.TryGetValue(lastBarDate, out iv)) && (!Double.IsNaN(iv)) && (iv > 0))
            {
                m_prevIv = iv;
                return(iv);
            }
            else
            {
                int barsCount = ContextBarsCount;
                if (barNum < barsCount - 1)
                {
                    // Если история содержит осмысленное значение, то оно уже содержится в failRes
                    return(failRes);
                }
                else
                {
                    #region Process last bar(s)
                    FinInfo baseFinInfo = optSer.UnderlyingAsset.FinInfo;
                    if (baseFinInfo.LastPrice == null)
                    {
                        string msg = "[IV ATM 2] (baseFinInfo.LastPrice == null)";
                        m_context.Log(msg, MessageType.Warning, false);
                        return(failRes);
                    }

                    double futPx = baseFinInfo.LastPrice.Value;
                    if (futPx <= Double.Epsilon)
                    {
                        return(failRes);
                    }

                    NotAKnotCubicSpline spline = null;
                    try
                    {
                        spline = IvOnF.PrepareExchangeSmileSpline(optSer, Double.MinValue, Double.MaxValue);
                    }
                    catch (ScriptException scriptEx)
                    {
                        m_context.Log(scriptEx.ToString(), MessageType.Error, false);
                        return(failRes);
                    }
                    catch (Exception ex)
                    {
                        m_context.Log(ex.ToString(), MessageType.Error, false);
                        return(failRes);
                    }

                    if (spline == null)
                    {
                        return(failRes);
                    }

                    try
                    {
                        double sigma;
                        if (spline.TryGetValue(futPx, out sigma) && (sigma > 0))
                        {
                            if (m_rescaleTime)
                            {
                                #region Зверская ветка по замене времени
                                double   ivAtm   = sigma;
                                DateTime expDate = optSer.ExpirationDate.Date + m_expiryTime;
                                DateTime now     = baseFinInfo.LastUpdate;

                                // 1. Надо перевести волатильность в абсолютную цену
                                // с учетом плоского календарного времени применяемого РТС
                                double plainTimeAsYears;
                                {
                                    double plainTimeAsDays;
                                    TimeToExpiry.GetDt(expDate, now, TimeRemainMode.PlainCalendar, false,
                                                       out plainTimeAsDays, out plainTimeAsYears);
                                }

                                // 2. Вычисляем 'нормальное' время
                                double timeAsDays, timeAsYears;
                                TimeToExpiry.GetDt(expDate, now, m_tRemainMode, false, out timeAsDays, out timeAsYears);
                                sigma = FinMath.RescaleIvToAnotherTime(plainTimeAsYears, ivAtm, timeAsYears);
                                if (DoubleUtil.IsPositive(sigma))
                                {
                                    // Это просто запись на диск. К успешности вычисления волы success отношения не имеет
                                    lock (ivSigmas)
                                    {
                                        bool success = IvOnF.TryWrite(m_context, UseGlobalCache, AllowGlobalReadWrite,
                                                                      GlobalSavePeriod, cashKey, ivSigmas, lastBarDate, sigma);
                                        m_prevIv = sigma;

                                        // Теперь надо вычислить безразмерный наклон кодом в классе SmileImitation5
                                        bool successSkew = IvOnF.TryCalcAndWriteSkews(m_context, spline, UseGlobalCache, AllowGlobalReadWrite,
                                                                                      GlobalSavePeriod, optSer.UnderlyingAsset.Symbol, expiry, futPx, lastBarDate,
                                                                                      m_tRemainMode, plainTimeAsYears, timeAsYears);

                                        return(sigma);
                                    }
                                }
                                else
                                {
                                    // Если перемасштабировать улыбку не получается придется эту точку проигнорировать
                                    // Надо ли сделать соответствующую запись в логе???
                                    sigma = Constants.NaN;
                                }
                                #endregion Зверская ветка по замене времени
                            }
                            else
                            {
                                lock (ivSigmas)
                                {
                                    bool success = IvOnF.TryWrite(m_context, UseGlobalCache, AllowGlobalReadWrite,
                                                                  GlobalSavePeriod, cashKey, ivSigmas, lastBarDate, sigma);
                                    m_prevIv = sigma;
                                    return(sigma);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        m_context.Log(ex.ToString(), MessageType.Error, false);
                    }

                    return(failRes);

                    #endregion Process last bar
                }
            }
        }
Пример #7
0
        private bool TryProcessSeries(IOptionSeries optSer, DateTime now, out double ivAtm)
        {
            ivAtm = Constants.NaN;
            if (optSer == null)
            {
                return(false);
            }

            Dictionary <DateTime, double> ivSigmas;

            #region Get cache
            DateTime expiry    = optSer.ExpirationDate.Date;
            string   cashKey   = IvOnF.GetCashKey(optSer.UnderlyingAsset.Symbol, expiry, m_rescaleTime, m_tRemainMode);
            object   globalObj = Context.LoadGlobalObject(cashKey, true);
            ivSigmas = globalObj as Dictionary <DateTime, double>;
            // PROD-3970 - 'Важный' объект
            if (ivSigmas == null)
            {
                var container = globalObj as NotClearableContainer;
                if ((container != null) && (container.Content != null))
                {
                    ivSigmas = container.Content as Dictionary <DateTime, double>;
                }
            }
            if (ivSigmas == null)
            {
                ivSigmas = new Dictionary <DateTime, double>();
            }
            #endregion Get cache

            ISecurity sec = optSer.UnderlyingAsset;
            int       len = sec.Bars.Count;
            if (len <= 0)
            {
                return(false);
            }

            FinInfo baseFinInfo = optSer.UnderlyingAsset.FinInfo;
            if (baseFinInfo.LastPrice == null)
            {
                string msg = "[IV ATM (all series)] (baseFinInfo.LastPrice == null)";
                m_context.Log(msg, MessageType.Warning, false);
                return(false);
            }

            double futPx = baseFinInfo.LastPrice.Value;
            if (futPx <= Double.Epsilon)
            {
                return(false);
            }

            NotAKnotCubicSpline spline = null;
            try
            {
                spline = IvOnF.PrepareExchangeSmileSpline(optSer, Double.MinValue, Double.MaxValue);
            }
            catch (ScriptException scriptEx)
            {
                m_context.Log(scriptEx.ToString(), MessageType.Error, false);
                return(false);
            }
            catch (Exception ex)
            {
                m_context.Log(ex.ToString(), MessageType.Error, false);
                return(false);
            }

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

            try
            {
                double sigma;
                if (spline.TryGetValue(futPx, out sigma) && (!Double.IsNaN(sigma)) && (sigma > 0))
                {
                    ivAtm = sigma;
                    DateTime lastBarDate = sec.Bars[len - 1].Date;

                    if (m_rescaleTime)
                    {
                        #region Зверская ветка по замене времени
                        DateTime expDate = optSer.ExpirationDate.Date + m_expiryTime;

                        // 1. Надо перевести волатильность в абсолютную цену
                        // с учетом плоского календарного времени применяемого РТС
                        double plainTimeAsYears;
                        {
                            double plainTimeAsDays;
                            TimeToExpiry.GetDt(expDate, now, TimeRemainMode.PlainCalendar,
                                               false, out plainTimeAsDays, out plainTimeAsYears);
                        }

                        // 2. Вычисляем 'нормальное' время
                        double timeAsDays, timeAsYears;
                        TimeToExpiry.GetDt(expDate, now, m_tRemainMode,
                                           false, out timeAsDays, out timeAsYears);
                        sigma = FinMath.RescaleIvToAnotherTime(plainTimeAsYears, ivAtm, timeAsYears);
                        if (DoubleUtil.IsPositive(sigma))
                        {
                            ivAtm = sigma;
                            // Это просто запись на диск. К успешности вычисления волы success отношения не имеет
                            bool success = IvOnF.TryWrite(m_context, true, true, 1, cashKey, ivSigmas,
                                                          lastBarDate, sigma);

                            // Теперь надо вычислить безразмерный наклон кодом в классе SmileImitation5
                            bool successSkew = IvOnF.TryCalcAndWriteSkews(m_context, spline, true, true, 1,
                                                                          optSer.UnderlyingAsset.Symbol, expiry, futPx, lastBarDate,
                                                                          m_tRemainMode, plainTimeAsYears, timeAsYears);

                            return(true);
                        }
                        else
                        {
                            // Если перемасштабировать улыбку не получается придется эту точку проигнорировать
                            // Надо ли сделать соответствующую запись в логе???
                            return(false);
                        }
                        #endregion Зверская ветка по замене времени
                    }
                    else
                    {
                        // Это просто запись на диск. К успешности вычисления волы success отношения не имеет
                        bool success = IvOnF.TryWrite(m_context, true, true, 1, cashKey, ivSigmas,
                                                      lastBarDate, sigma);
                        return(true);
                    }
                }
            }
            catch (ScriptException scriptEx)
            {
                m_context.Log(scriptEx.ToString(), MessageType.Error, false);
            }
            catch (Exception ex)
            {
                m_context.Log(ex.ToString(), MessageType.Error, false);
                //throw;
            }

            return(false);
        }