public SecurityTSlab(ISecurity compressedSecurity, ISecurity baseSecurity)
 {
     this.baseSecurity = baseSecurity;
     finInfo           = baseSecurity.FinInfo;
     InitializeSecurity(compressedSecurity);
     CompareBarsBaseSecurityWithCompressedSecurity();
 }
示例#2
0
        public FinInfo GetDFNPDataByID(int DataCaptYM, string DeptId)
        {
            Dictionary <string, object> sqlParamDictionary = new Dictionary <string, object>();

            sqlParamDictionary.Add("DataCaptYM", DataCaptYM);
            sqlParamDictionary.Add("DeptID", DeptId);
            IDbCommand    command    = new SqlCommand().GetCommandWithParameters(sqlParamDictionary, _SELECT_DFNP_Data);
            SqlConnection connection = DBConnectionHelper.OpenNewSqlConnection(this.ConnectionString);

            command.Connection = connection;
            FinInfo finInfo = EntityMapper.MapSingle <FinInfo>(command.ExecuteReader());

            DBConnectionHelper.CloseSqlConnection(connection);
            return(finInfo);
        }
示例#3
0
        protected override double?GetValue(FinInfo finInfo)
        {
            if (finInfo == null || finInfo.Security == null)
            {
                return(1);
            }

            var lastPrice = finInfo.LastPrice ?? 0.0;
            var tick      = finInfo.Security.GetTick(lastPrice);

            if (!DoubleUtil.IsPositive(tick))
            {
                tick = Math.Pow(10, -finInfo.Security.Decimals);
            }

            return(tick);
        }
        public void GetDFNPData(int _dataCaptYM)
        {
            FormsRepository formsRepository = new FormsRepository();
            var             DataCaptYM      = SessionManager.DataCaptYR > 0 ? SessionManager.DataCaptYR : (_dataCaptYM > 0 ? _dataCaptYM : 0);
            string          deptID          = string.IsNullOrEmpty(SessionManager.EmpDeptID) ? SessionManager.DeptID : SessionManager.EmpDeptID;

            finInfo = formsRepository.GetDFNPDataByID(DataCaptYM, deptID);

            if (finInfo == null)
            {
                finInfo = new FinInfo();
            }

            if (finInfo.DataStatus == 0)
            {
                finInfo.DataCaptYM     = DataCaptYM;
                finInfo.DataStatus     = (int)DataAccess.Enum.DataStatus.DataEntryStartedbyOperator;
                finInfo.DataStatusName = (DataAccess.Enum.DataStatus.DataEntryStartedbyOperator).GetStringValue();
            }
        }
示例#5
0
 protected override double?GetValue(FinInfo finInfo)
 {
     return(finInfo.SellDeposit);
 }
示例#6
0
 protected override double?GetValue(FinInfo finInfo)
 {
     return(finInfo.BuyCount);
 }
示例#7
0
 protected abstract double?GetValue(FinInfo finInfo);
示例#8
0
        protected override bool TryCalculate(Dictionary <DateTime, double> history, DateTime now, int barNum, object[] args, out double val)
        {
            ISecurity     sec    = (ISecurity)args[0];
            IOptionSeries optSer = (IOptionSeries)args[1];

            val = Double.NaN;

            double px;

            #region switch(m_pxMode)
            switch (m_pxMode)
            {
            case BasePxMode.FixedPx:
                px = m_fixedPx;
                break;

            case BasePxMode.LastTrade:
                if (sec.FinInfo.LastPrice.HasValue)
                {
                    px = sec.FinInfo.LastPrice.Value;
                }
                else
                {
                    return(false);
                }
                break;

            case BasePxMode.BidAskMidPoint:
            {
                FinInfo info = sec.FinInfo;
                if (info.Ask.HasValue && info.Bid.HasValue && info.AskSize.HasValue &&
                    info.BidSize.HasValue && (info.AskSize.Value > 0) && (info.BidSize.Value > 0))
                {
                    px = (info.Ask.Value + info.Bid.Value) / 2;
                }
                else if (info.Ask.HasValue && info.AskSize.HasValue && (info.AskSize.Value > 0))
                {
                    px = info.Ask.Value;
                }
                else if (info.Bid.HasValue && info.BidSize.HasValue && (info.BidSize.Value > 0))
                {
                    px = info.Bid.Value;
                }
                else
                {
                    // Приемлемо ли такое решение?
                    if (info.LastPrice.HasValue)
                    {
                        px = info.LastPrice.Value;
                    }
                    else
                    {
                        return(false);
                    }
                }
            }
            break;

            case BasePxMode.TheorPxBased:
            {
                if (optSer == null)
                {
                    return(false);
                }

                IOptionStrikePair[] pairs = optSer.GetStrikePairs().ToArray();
                IOptionStrikePair   pair  = pairs[pairs.Length / 2];

                if ((pair.PutFinInfo.TheoreticalPrice == null) ||
                    (pair.CallFinInfo.TheoreticalPrice == null))
                {
                    return(false);
                }

                double putPx  = pair.PutFinInfo.TheoreticalPrice.Value;
                double callPx = pair.CallFinInfo.TheoreticalPrice.Value;
                px = callPx - putPx + pair.Strike;
            }
            break;

            default:
                throw new NotImplementedException("pxMode:" + m_pxMode);
            }
            #endregion switch(m_pxMode)

            val = px;

            return(true);
        }
示例#9
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));
        }
示例#10
0
        /// <summary>
        /// Метод под флаг TemplateTypes.SECURITY, чтобы подключаться к источнику-БА
        /// </summary>
        public double Execute(ISecurity sec, int barNum)
        {
            double failRes = Constants.NaN;

            if (m_repeatLastPx)
            {
                failRes = Double.IsNaN(m_prevPx) ? Constants.NaN : m_prevPx;
            }

            Dictionary <DateTime, double> basePrices;

            #region Get cache
            {
                string cashKey = VariableId + "_basePrices";
                basePrices = Context.LoadObject(cashKey) as Dictionary <DateTime, double>;
                if (basePrices == null)
                {
                    basePrices = new Dictionary <DateTime, double>();
                    Context.StoreObject(cashKey, basePrices);
                }
            }
            #endregion Get cache

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

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

            double   px;
            DateTime lastBarDate = sec.Bars[barNum].Date;
            if ((basePrices.TryGetValue(lastBarDate, out px)) && DoubleUtil.IsPositive(px))
            {
                m_prevPx = px;
                // Раз мы нашли валидную цену в архиве, то можно обновить failRes
                failRes = px;
            }

            // Цену в архиве нашли, теперь надо проверить свежие сведения.
            {
                int barsCount = ContextBarsCount;
                if (barNum < barsCount - 1)
                {
                    // Если история содержит осмысленное значение, то оно уже содержится в failRes
                    return(failRes);
                }
                else
                {
                    #region Process last bar(s)

                    #region switch(m_pxMode)
                    switch (m_pxMode)
                    {
                    case BasePxMode.FixedPx:
                        px       = m_fixedPx;
                        m_prevPx = px;
                        break;

                    case BasePxMode.LastTrade:
                        if (sec.FinInfo.LastPrice.HasValue)
                        {
                            px       = sec.FinInfo.LastPrice.Value;
                            m_prevPx = px;
                        }
                        else
                        {
                            px = failRes;
                        }
                        break;

                    case BasePxMode.BidAskMidPoint:
                    {
                        FinInfo info = sec.FinInfo;
                        if (info.Ask.HasValue && info.Bid.HasValue && info.AskSize.HasValue &&
                            info.BidSize.HasValue && (info.AskSize.Value > 0) && (info.BidSize.Value > 0))
                        {
                            px       = (info.Ask.Value + info.Bid.Value) / 2;
                            m_prevPx = px;
                        }
                        else if (info.Ask.HasValue && info.AskSize.HasValue && (info.AskSize.Value > 0))
                        {
                            px       = info.Ask.Value;
                            m_prevPx = px;
                        }
                        else if (info.Bid.HasValue && info.BidSize.HasValue && (info.BidSize.Value > 0))
                        {
                            px       = info.Bid.Value;
                            m_prevPx = px;
                        }
                        else
                        {
                            // Приемлемо ли такое решение?
                            if (info.LastPrice.HasValue)
                            {
                                px       = info.LastPrice.Value;
                                m_prevPx = px;
                            }
                            else
                            {
                                px = failRes;
                            }
                        }
                    }
                    break;

                    default:
                        throw new NotImplementedException("pxMode:" + m_pxMode);
                    }
                    #endregion switch(m_pxMode)

                    basePrices[lastBarDate] = px;

                    double displayValue = FixedValue.ConvertToDisplayUnits(m_valueMode, px);
                    m_displayPrice.Value = displayValue;

                    return(px);

                    #endregion Process last bar(s)
                }
            }
        }
 public SecurityTSlab(ISecurity security)
 {
     finInfo = security.FinInfo;
     InitializeSecurity(security);
 }
示例#12
0
        /// <summary>
        /// Обработчик под тип входных данных OPTION_SERIES
        /// </summary>
        public InteractiveSeries Execute(IOptionSeries optSer, IList <double> rates)
        {
            InteractiveSeries res = m_context.LoadObject(VariableId + "theorSmile") as InteractiveSeries;

            if (res == null)
            {
                res = new InteractiveSeries(); // Здесь так надо -- мы делаем новую улыбку
                m_context.StoreObject(VariableId + "theorSmile", res);
            }

            if (optSer == null)
            {
                return(res);
            }

            int len = optSer.UnderlyingAsset.Bars.Count;

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

            FinInfo bSecFinInfo = optSer.UnderlyingAsset.FinInfo;

            if (!bSecFinInfo.LastPrice.HasValue)
            {
                return(res);
            }

            if (rates.Count <= 0)
            {
                //throw new ScriptException("There should be some values in second argument 'rates'.");
                return(res);
            }

            //IDataBar bar = optSer.UnderlyingAsset.Bars[len - 1];
            double futPx = bSecFinInfo.LastPrice.Value;
            // ФОРТС использует плоское календарное время
            DateTime optExpiry = optSer.ExpirationDate.Date.Add(m_expiryTime);
            double   dT        = (optExpiry - bSecFinInfo.LastUpdate).TotalYears();
            double   ratePct   = rates[rates.Count - 1];

            if (Double.IsNaN(dT) || (dT < Double.Epsilon))
            {
                // [{0}] Time to expiry must be positive value. dT:{1}
                string msg = RM.GetStringFormat("OptHandlerMsg.TimeMustBePositive", GetType().Name, dT);
                m_context.Log(msg, MessageType.Error, true);
                return(res);
            }

            if (Double.IsNaN(futPx) || (futPx < Double.Epsilon))
            {
                // [{0}] Base asset price must be positive value. F:{1}
                string msg = RM.GetStringFormat("OptHandlerMsg.FutPxMustBePositive", GetType().Name, futPx);
                m_context.Log(msg, MessageType.Error, true);
                return(res);
            }

            if (Double.IsNaN(ratePct))
            {
                //throw new ScriptException("Argument 'rate' contains NaN for some strange reason. rate:" + rate);
                return(res);
            }

            // TODO: переписаться на обновление старых значений
            //res.ControlPoints.Clear();
            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            List <double> xs = new List <double>();
            List <double> ys = new List <double>();

            IOptionStrikePair[] pairs = (from pair in optSer.GetStrikePairs()
                                         //orderby pair.Strike ascending -- уже отсортировано!
                                         select pair).ToArray();
            for (int j = 0; j < pairs.Length; j++)
            {
                bool showPoint          = true;
                IOptionStrikePair sInfo = pairs[j];
                double            k     = sInfo.Strike;
                //// Сверхдалекие страйки игнорируем
                //if ((sInfo.Strike < m_minStrike) || (m_maxStrike < sInfo.Strike))
                //{
                //    showPoint = false;
                //}

                if ((sInfo.PutFinInfo == null) || (sInfo.CallFinInfo == null) ||
                    (!sInfo.PutFinInfo.TheoreticalPrice.HasValue) || (!sInfo.PutFinInfo.Volatility.HasValue) ||
                    (sInfo.PutFinInfo.TheoreticalPrice.Value <= 0) || (sInfo.PutFinInfo.Volatility.Value <= 0) ||
                    (!sInfo.CallFinInfo.TheoreticalPrice.HasValue) || (!sInfo.CallFinInfo.Volatility.HasValue) ||
                    (sInfo.CallFinInfo.TheoreticalPrice.Value <= 0) || (sInfo.CallFinInfo.Volatility.Value <= 0))
                {
                    continue;
                }

                double prec;
                // Биржа шлет несогласованную улыбку
                //double virtualExchangeF = sInfo.CallFinInfo.TheoreticalPrice.Value - sInfo.PutFinInfo.TheoreticalPrice.Value + sInfo.Strike;
                if ((m_optionType == StrikeType.Any) || (m_optionType == StrikeType.Put))
                {
                    double optSigma = sInfo.PutFinInfo.Volatility.Value;
                    if ((!DoubleUtil.IsOne(m_multPx)) || (!DoubleUtil.IsZero(m_shiftPx)))
                    {
                        double optPx = sInfo.PutFinInfo.TheoreticalPrice.Value * m_multPx + m_shiftPx * sInfo.Tick;
                        if ((optPx <= 0) || (Double.IsNaN(optPx)))
                        {
                            optSigma = 0;
                        }
                        else
                        {
                            optSigma = FinMath.GetOptionSigma(futPx, k, dT, optPx, ratePct, false, out prec);
                        }
                    }

                    double vol = optSigma;

                    // ReSharper disable once UseObjectOrCollectionInitializer
                    InteractivePointActive ip = new InteractivePointActive(k, vol);
                    ip.Geometry = Geometries.Ellipse;
                    ip.Color    = AlphaColors.Cyan;
                    ip.Tooltip  = String.Format("K:{0}; IV:{1:0.00}", k, Constants.PctMult * optSigma);

                    if (showPoint && (vol > 0))
                    {
                        controlPoints.Add(new InteractiveObject(ip));
                    }

                    if ((xs.Count <= 0) ||
                        (!DoubleUtil.AreClose(k, xs[xs.Count - 1])))
                    {
                        xs.Add(k);
                        ys.Add(vol);
                    }
                }

                if ((m_optionType == StrikeType.Any) || (m_optionType == StrikeType.Call))
                {
                    double optSigma = sInfo.CallFinInfo.Volatility.Value;
                    if ((!DoubleUtil.IsOne(m_multPx)) || (!DoubleUtil.IsZero(m_shiftPx)))
                    {
                        double optPx = sInfo.CallFinInfo.TheoreticalPrice.Value * m_multPx + m_shiftPx * sInfo.Tick;
                        if ((optPx <= 0) || (Double.IsNaN(optPx)))
                        {
                            optSigma = 0;
                        }
                        else
                        {
                            optSigma = FinMath.GetOptionSigma(futPx, k, dT, optPx, ratePct, true, out prec);
                        }
                    }

                    double vol = optSigma;

                    // ReSharper disable once UseObjectOrCollectionInitializer
                    InteractivePointActive ip = new InteractivePointActive(k, vol);
                    ip.Geometry = Geometries.Ellipse;
                    ip.Color    = AlphaColors.DarkCyan;
                    ip.Tooltip  = String.Format("K:{0}; IV:{1:0.00}", k, Constants.PctMult * optSigma);

                    if (showPoint && (vol > 0))
                    {
                        controlPoints.Add(new InteractiveObject(ip));
                    }

                    if ((xs.Count <= 0) ||
                        (!DoubleUtil.AreClose(k, xs[xs.Count - 1])))
                    {
                        xs.Add(k);
                        ys.Add(vol);
                    }
                }
            }

            res.ControlPoints = new ReadOnlyCollection <InteractiveObject>(controlPoints);

            var      baseSec    = optSer.UnderlyingAsset;
            DateTime scriptTime = baseSec.Bars[baseSec.Bars.Count - 1].Date;

            // ReSharper disable once UseObjectOrCollectionInitializer
            SmileInfo info = new SmileInfo();

            info.F            = futPx;
            info.dT           = dT;
            info.Expiry       = optSer.ExpirationDate;
            info.ScriptTime   = scriptTime;
            info.RiskFreeRate = ratePct;
            info.BaseTicker   = baseSec.Symbol;

            try
            {
                if (xs.Count >= BaseCubicSpline.MinNumberOfNodes)
                {
                    NotAKnotCubicSpline spline = new NotAKnotCubicSpline(xs, ys);

                    info.ContinuousFunction   = spline;
                    info.ContinuousFunctionD1 = spline.DeriveD1();

                    res.Tag = info;
                }
            }
            catch (Exception ex)
            {
                m_context.Log(ex.ToString(), MessageType.Error, true);
                return(Constants.EmptySeries);
            }

            return(res);
        }
示例#13
0
        /// <summary>
        /// Обработчик под тип входных данных OPTION_SERIES
        /// </summary>
        public InteractiveSeries Execute(double price, double trueTimeToExpiry, IOptionSeries optSer, double ratePct, int barNum)
        {
            int barsCount = ContextBarsCount;

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

            // PROD-5952 - Не надо дергать стакан без нужды
            //optSer.UnderlyingAsset.UpdateQueueData();
            FinInfo bSecFinInfo = optSer.UnderlyingAsset.FinInfo;

            if (bSecFinInfo.LastPrice == null)
            {
                return(Constants.EmptySeries);
            }

            double futPx = price;
            // ФОРТС использует плоское календарное время
            DateTime optExpiry = optSer.ExpirationDate.Date.Add(m_expiryTime);
            double   dT        = (optExpiry - bSecFinInfo.LastUpdate).TotalYears();

            if (Double.IsNaN(dT) || (dT < Double.Epsilon))
            {
                // [{0}] Time to expiry must be positive value. dT:{1}
                string msg = RM.GetStringFormat("OptHandlerMsg.TimeMustBePositive", GetType().Name, dT);
                m_context.Log(msg, MessageType.Error, true);
                return(Constants.EmptySeries);
            }

            if (Double.IsNaN(futPx) || (futPx < Double.Epsilon))
            {
                // [{0}] Base asset price must be positive value. F:{1}
                string msg = RM.GetStringFormat("OptHandlerMsg.FutPxMustBePositive", GetType().Name, futPx);
                m_context.Log(msg, MessageType.Error, true);
                return(Constants.EmptySeries);
            }

            if (Double.IsNaN(trueTimeToExpiry) || (trueTimeToExpiry < Double.Epsilon))
            {
                string msg = String.Format("[{0}] trueTimeToExpiry must be positive value. dT:{1}", GetType().Name, trueTimeToExpiry);
                m_context.Log(msg, MessageType.Error, true);
                return(Constants.EmptySeries);
            }

            if (Double.IsNaN(ratePct))
            {
                //throw new ScriptException("Argument 'ratePct' contains NaN for some strange reason. rate:" + rate);
                return(Constants.EmptySeries);
            }

            double effectiveTime = m_rescaleTime ? trueTimeToExpiry : dT;

            List <double> xs = new List <double>();
            List <double> ys = new List <double>();

            IOptionStrikePair[] pairs = (from pair in optSer.GetStrikePairs()
                                         //orderby pair.Strike ascending -- уже отсортировано!
                                         select pair).ToArray();

            if (pairs.Length < 2)
            {
                string msg = String.Format("[{0}] optSer must contain few strike pairs. pairs.Length:{1}", GetType().Name, pairs.Length);
                m_context.Log(msg, MessageType.Warning, true);
                return(Constants.EmptySeries);
            }

            for (int j = 0; j < pairs.Length; j++)
            {
                //bool showPoint = true;
                IOptionStrikePair sInfo = pairs[j];
                double            k     = sInfo.Strike;
                //// Сверхдалекие страйки игнорируем
                //if ((k < m_minStrike) || (m_maxStrike < k))
                //{
                //    showPoint = false;
                //}

                if ((sInfo.PutFinInfo == null) || (sInfo.CallFinInfo == null) ||
                    (!sInfo.PutFinInfo.TheoreticalPrice.HasValue) || (!sInfo.PutFinInfo.Volatility.HasValue) ||
                    (sInfo.PutFinInfo.TheoreticalPrice.Value <= 0) || (sInfo.PutFinInfo.Volatility.Value <= 0) ||
                    (!sInfo.CallFinInfo.TheoreticalPrice.HasValue) || (!sInfo.CallFinInfo.Volatility.HasValue) ||
                    (sInfo.CallFinInfo.TheoreticalPrice.Value <= 0) || (sInfo.CallFinInfo.Volatility.Value <= 0))
                {
                    continue;
                }

                // Биржа шлет несогласованную улыбку
                //double virtualExchangeF = sInfo.CallFinInfo.TheoreticalPrice.Value - sInfo.PutFinInfo.TheoreticalPrice.Value + sInfo.Strike;
                if ((m_optionType == StrikeType.Any) || (m_optionType == StrikeType.Put))
                {
                    double optSigma = sInfo.PutFinInfo.Volatility.Value;
                    if (m_rescaleTime)
                    {
                        // optSigma = FinMath.GetOptionSigma(futPx, k, effectiveTime, optPx, 0, false);
                        optSigma = FinMath.RescaleIvToAnotherTime(dT, optSigma, trueTimeToExpiry);
                    }

                    double optPx = sInfo.PutFinInfo.TheoreticalPrice ?? Double.NaN;

                    //// ReSharper disable once UseObjectOrCollectionInitializer
                    //InteractivePointActive ip = new InteractivePointActive(k, optSigma);
                    //ip.IsActive = m_showNodes;
                    //ip.Geometry = Geometries.Ellipse;
                    //ip.Color = System.Windows.Media.Colors.Cyan;
                    //ip.Tooltip = String.Format("K:{0}; IV:{1:0.00}; Px:{2}\r\ndT:{3:0.000}; Date:{4}",
                    //    k, Constants.PctMult * optSigma, optPx,
                    //    FixedValue.ConvertToDisplayUnits(FixedValueMode.YearsAsDays, effectiveTime),
                    //    bSecFinInfo.LastUpdate.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture));

                    if (optSigma > 0)
                    {
                        // Это условие позволяет не вставлять точки с совпадающими абсциссами
                        if ((xs.Count <= 0) ||
                            (!DoubleUtil.AreClose(k, xs[xs.Count - 1])))
                        {
                            xs.Add(k);
                            ys.Add(optSigma);
                        }
                    }
                }

                if ((m_optionType == StrikeType.Any) || (m_optionType == StrikeType.Call))
                {
                    double optSigma = sInfo.CallFinInfo.Volatility.Value;
                    if (m_rescaleTime)
                    {
                        // optSigma = FinMath.GetOptionSigma(futPx, k, effectiveTime, optPx, 0, false);
                        optSigma = FinMath.RescaleIvToAnotherTime(dT, optSigma, trueTimeToExpiry);
                    }

                    double optPx = sInfo.CallFinInfo.TheoreticalPrice ?? Double.NaN;

                    //// ReSharper disable once UseObjectOrCollectionInitializer
                    //InteractivePointActive ip = new InteractivePointActive(k, optSigma);
                    //ip.IsActive = m_showNodes;
                    //ip.Geometry = Geometries.Ellipse;
                    //ip.Color = System.Windows.Media.Colors.Cyan;
                    //ip.Tooltip = String.Format("K:{0}; IV:{1:0.00}; Px:{2}\r\ndT:{3:0.000}; Date:{4}",
                    //    k, Constants.PctMult * optSigma, optPx,
                    //    FixedValue.ConvertToDisplayUnits(FixedValueMode.YearsAsDays, effectiveTime),
                    //    bSecFinInfo.LastUpdate.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture));

                    if (optSigma > 0)
                    {
                        // Это условие позволяет не вставлять точки с совпадающими абсциссами
                        if ((xs.Count <= 0) ||
                            (!DoubleUtil.AreClose(k, xs[xs.Count - 1])))
                        {
                            xs.Add(k);
                            ys.Add(optSigma);
                        }
                    }
                }
            }

            #region 3. Строим сплайн по биржевой улыбке с узлами в страйках
            NotAKnotCubicSpline spline = null, splineD1 = null;
            try
            {
                if (xs.Count >= BaseCubicSpline.MinNumberOfNodes)
                {
                    spline   = new NotAKnotCubicSpline(xs, ys);
                    splineD1 = spline.DeriveD1();
                }
                else
                {
                    return(Constants.EmptySeries);
                }
            }
            catch (Exception ex)
            {
                string msg = String.Format("bSecFinInfo.LastUpdate:{0}; Bars.Last.Date:{1}\r\n\r\nException:{2}",
                                           bSecFinInfo.LastUpdate, optSer.UnderlyingAsset.Bars[optSer.UnderlyingAsset.Bars.Count - 1].Date, ex);
                m_context.Log(msg, MessageType.Error, true);
                return(Constants.EmptySeries);
            }
            #endregion 3. Строим сплайн по биржевой улыбке с узлами в страйках

            #region 5. С помощью сплайна уже можно строить гладкую улыбку
            double futStep = optSer.UnderlyingAsset.Tick;
            double dK = pairs[1].Strike - pairs[0].Strike;
            SortedDictionary <double, IOptionStrikePair> strikePrices;
            if (!SmileImitation5.TryPrepareImportantPoints(pairs, futPx, futStep, -1, out strikePrices))
            {
                string msg = String.Format("[WARNING:{0}] It looks like there is no suitable points for the smile. pairs.Length:{1}", GetType().Name, pairs.Length);
                m_context.Log(msg, MessageType.Warning, true);
                return(Constants.EmptySeries);
            }

            List <InteractiveObject> controlPoints = new List <InteractiveObject>();
            //for (int j = 0; j < pairs.Length; j++)
            foreach (var kvp in strikePrices)
            {
                bool   showPoint = (kvp.Value != null);
                double k         = kvp.Key;
                double sigma;
                if (!spline.TryGetValue(k, out sigma))
                {
                    continue;
                }
                double vol = sigma;

                if (Double.IsNaN(sigma) || Double.IsInfinity(sigma) || (sigma < Double.Epsilon))
                {
                    continue;
                }

                InteractivePointLight ip;
                if (m_showNodes && showPoint)
                {
                    // Как правило, эта ветка вообще не используется,
                    // потому что я не смотрю узлы биржевой улыбки.
                    double optPx = Double.NaN;
                    // ReSharper disable once UseObjectOrCollectionInitializer
                    InteractivePointActive tip = new InteractivePointActive(k, vol);
                    tip.IsActive = m_showNodes && showPoint;
                    tip.Geometry = Geometries.Ellipse;
                    tip.Color    = AlphaColors.Cyan;
                    tip.Tooltip  = String.Format("K:{0}; IV:{1:P2}; Px:{2}\r\ndT:{3:0.000}; Date:{4}",
                                                 k, vol, optPx,
                                                 FixedValue.ConvertToDisplayUnits(FixedValueMode.YearsAsDays, effectiveTime),
                                                 bSecFinInfo.LastUpdate.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture));
                    ip = tip;
                }
                else
                {
                    ip = new InteractivePointLight(k, vol);
                }

                InteractiveObject obj = new InteractiveObject(ip);
                controlPoints.Add(obj);
            }
            #endregion 5. С помощью сплайна уже можно строить гладкую улыбку

            // ReSharper disable once UseObjectOrCollectionInitializer
            InteractiveSeries res = new InteractiveSeries(); // Здесь так надо -- мы делаем новую улыбку
            res.ControlPoints = new ReadOnlyCollection <InteractiveObject>(controlPoints);

            var      baseSec    = optSer.UnderlyingAsset;
            DateTime scriptTime = baseSec.Bars[baseSec.Bars.Count - 1].Date;

            // ReSharper disable once UseObjectOrCollectionInitializer
            SmileInfo info = new SmileInfo();
            info.F            = futPx;
            info.dT           = effectiveTime;
            info.Expiry       = optSer.ExpirationDate;
            info.ScriptTime   = scriptTime;
            info.RiskFreeRate = ratePct;
            info.BaseTicker   = baseSec.Symbol;

            info.ContinuousFunction   = spline;
            info.ContinuousFunctionD1 = splineD1;

            res.Tag = info;

            return(res);
        }
示例#14
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
                }
            }
        }
示例#15
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);
        }