示例#1
0
        public double MakeDeal(ISecurity source, IOptionStrike strike, ISecurity priceSec, double strikePrice,
                               bool signal, int barNum, bool isCall)
        {
            var optionLot  = strike.LotTick;
            var strikeStep = strike.Tick;
            var sigma      = GetVolatility(source)[barNum];
            var ct         = source.Bars[barNum].Date;
            var dT         = ct.GetDt(Expiration);
            var price      = priceSec.Bars[barNum].Close;
            var optPx      = strikePrice.GetOptPx(strikeStep, isCall, price, dT, sigma);

            if (!signal)
            {
                return(optPx);
            }
            var prefix = isCall ? 'C' : 'P';
            var name   = $"{prefix}{ExpPrefix}{strikePrice:0}";
            var oldPos = source.Positions.GetLastActiveForSignal(name, barNum);

            if (oldPos == null)
            {
                source.Positions.MakeVirtualPosition(barNum + 1, optionLot, optPx, name);
            }
            else
            {
                var shares = oldPos.GetShares(barNum);
                if (shares < MaxShares && oldPos.GetPositionLastPrice(barNum) > optPx)
                {
                    oldPos.VirtualChange(barNum + 1, optPx, shares + optionLot, $"C-{name}");
                }
            }

            return(optPx);
        }
示例#2
0
        protected override void FillStrikeInfo(IOptionStrike optionStrike, StrikeInfo stInfo)
        {
            switch (optionStrike.StrikeType)
            {
            case StrikeType.Call:
                stInfo.Call = optionStrike.FinInfo.Ask ?? Constants.NaN;
                break;

            case StrikeType.Put:
                stInfo.Put = optionStrike.FinInfo.Ask ?? Constants.NaN;
                break;

            default:
                return;
            }
        }
示例#3
0
        /// <summary>
        /// Обработчик под тип входных данных OPTION_SERIES
        /// </summary>
        public IList <Double2> Execute(IOptionSeries optSer)
        {
            List <Double2> res = new List <Double2>();

            IOptionStrike[] strikes = (from strike in optSer.GetStrikes()
                                       orderby strike.Strike ascending
                                       select strike).ToArray();
            for (int j = 0; j < strikes.Length; j++)
            {
                IOptionStrike sInfo = strikes[j];
                if ((sInfo.FinInfo == null) || (!sInfo.FinInfo.TheoreticalPrice.HasValue))
                {
                    continue;
                }

                double optPx = sInfo.FinInfo.TheoreticalPrice.Value;
                optPx *= m_multPx;
                optPx += m_addPx * sInfo.Security.SecurityDescription.GetTick(sInfo.FinInfo.TheoreticalPrice.Value);

                res.Add(new Double2(sInfo.Strike, optPx));
            }

            return(res);
        }
示例#4
0
        /// <summary>
        /// Метод под флаг TemplateTypes.INTERACTIVESPLINE
        /// </summary>
        public InteractiveSeries Execute(InteractiveSeries smile, IOptionSeries optSer, double scaleMult, int barNum)
        {
            if ((smile == null) || (optSer == null))
            {
                return(Constants.EmptySeries);
            }

            int barsCount = m_context.BarsCount;

            if (!m_context.IsLastBarUsed)
            {
                barsCount--;
            }
            if (barNum < barsCount - 1)
            {
                return(Constants.EmptySeries);
            }

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

            if ((oldInfo == null) || (oldInfo.ContinuousFunction == null))
            {
                return(Constants.EmptySeries);
            }

            double futPx = oldInfo.F;
            double dT    = oldInfo.dT;

            if (m_executeCommand)
            {
                string msg = String.Format("[{0}.StartButton] Strike: {1}", GetType().Name, m_strike);
                m_context.Log(msg, MessageType.Info, false);
            }

            #region 1. Список страйков
            HashSet <string> serList = StrikeList;
            serList.Clear();

            IOptionStrikePair[] pairs;
            if (Double.IsNaN(m_strikeStep) || (m_strikeStep <= Double.Epsilon))
            {
                pairs = optSer.GetStrikePairs().ToArray();
            }
            else
            {
                // Выделяем страйки, которые нацело делятся на StrikeStep
                pairs = (from p in optSer.GetStrikePairs()
                         let test = m_strikeStep * Math.Round(p.Strike / m_strikeStep)
                                    where DoubleUtil.AreClose(p.Strike, test)
                                    select p).ToArray();

                // [2015-12-24] Если шаг страйков по ошибке задан совершенно неправильно,
                // то в коллекцию ставим все имеющиеся страйки.
                // Пользователь потом разберется
                if (pairs.Length <= 0)
                {
                    pairs = optSer.GetStrikePairs().ToArray();
                }
            }
            //if (pairs.Length < 2)
            //    return Constants.EmptyListDouble;

            foreach (IOptionStrikePair pair in pairs)
            {
                double k = pair.Strike;
                serList.Add(k.ToString(StrikeFormat, CultureInfo.InvariantCulture));
            }
            #endregion 1. Список страйков

            InteractiveSeries        res           = Constants.EmptySeries;
            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            #region 2. Формируем улыбку просто для отображения текущего положения потенциальной котировки
            // При нулевом рабочем объёме не утруждаемся рисованием лишних линий
            if (!DoubleUtil.IsZero(m_qty))
            {
                for (int j = 0; j < pairs.Length; j++)
                {
                    var    pair  = pairs[j];
                    double sigma = oldInfo.ContinuousFunction.Value(pair.Strike) + m_shiftIv;
                    if (!DoubleUtil.IsPositive(sigma))
                    {
                        //string msg = String.Format("[DEBUG:{0}] Invalid sigma:{1} for strike:{2}", GetType().Name, sigma, nodeInfo.Strike);
                        //m_context.Log(msg, MessageType.Warning, true);
                        continue;
                    }

                    //bool isCall = (futPx <= pair.Strike);
                    bool isCall;
                    if (m_optionType == StrikeType.Call)
                    {
                        isCall = true;
                    }
                    else if (m_optionType == StrikeType.Put)
                    {
                        isCall = false;
                    }
                    else
                    {
                        isCall = (futPx <= pair.Strike);
                    }

                    StrikeType optionType = isCall ? StrikeType.Call : StrikeType.Put;
                    Contract.Assert(pair.Tick < 1, $"#1 На тестовом контуре Дерибит присылает неправильный шаг цены! Tick:{pair.Tick}; Decimals:{pair.Put.Security.Decimals}");
                    double theorOptPxDollars = FinMath.GetOptionPrice(futPx, pair.Strike, dT, sigma, oldInfo.RiskFreeRate, isCall);
                    // Сразу(!!!) переводим котировку из баксов в битки
                    double theorOptPxBitcoins = theorOptPxDollars / scaleMult;

                    // Сдвигаем цену в долларах (с учетом ш.ц. в баксах)
                    theorOptPxDollars += m_shiftPriceStep * pair.Tick * scaleMult;
                    theorOptPxDollars  = Math.Round(theorOptPxDollars / (pair.Tick * scaleMult)) * (pair.Tick * scaleMult);

                    // Сдвигаем цену в биткойнах (с учетом ш.ц. в битках)
                    theorOptPxBitcoins += m_shiftPriceStep * pair.Tick;
                    theorOptPxBitcoins  = Math.Round(theorOptPxBitcoins / pair.Tick) * pair.Tick;
                    if ((!DoubleUtil.IsPositive(theorOptPxBitcoins)) || (!DoubleUtil.IsPositive(theorOptPxDollars)))
                    {
                        //string msg = String.Format("[DEBUG:{0}] Invalid theorOptPx:{1} for strike:{2}", GetType().Name, theorOptPx, nodeInfo.Strike);
                        //m_context.Log(msg, MessageType.Warning, true);
                        continue;
                    }

                    // Пересчитываем сигму обратно, ЕСЛИ мы применили сдвиг цены в абсолютном выражении
                    if (m_shiftPriceStep != 0)
                    {
                        // Обратный пересчет в волатильность
                        sigma = FinMath.GetOptionSigma(futPx, pair.Strike, dT, theorOptPxDollars, oldInfo.RiskFreeRate, isCall);
                        if (!DoubleUtil.IsPositive(sigma))
                        {
                            //string msg = String.Format("[DEBUG:{0}] Invalid sigma:{1} for strike:{2}", GetType().Name, sigma, nodeInfo.Strike);
                            //m_context.Log(msg, MessageType.Warning, true);
                            continue;
                        }
                    }

                    // ReSharper disable once UseObjectOrCollectionInitializer
                    SmileNodeInfo nodeInfo = new SmileNodeInfo();
                    var           secDesc  = isCall ? pair.CallFinInfo.Security : pair.PutFinInfo.Security;
                    nodeInfo.F            = oldInfo.F;
                    nodeInfo.dT           = oldInfo.dT;
                    nodeInfo.RiskFreeRate = oldInfo.RiskFreeRate;
                    nodeInfo.Strike       = pair.Strike;
                    nodeInfo.Sigma        = sigma;
                    nodeInfo.OptPx        = theorOptPxBitcoins;
                    nodeInfo.OptionType   = isCall ? StrikeType.Call : StrikeType.Put;
                    nodeInfo.Pair         = pair;

                    nodeInfo.Symbol   = secDesc.Name;
                    nodeInfo.DSName   = secDesc.DSName;
                    nodeInfo.Expired  = secDesc.Expired;
                    nodeInfo.FullName = secDesc.FullName;

                    // ReSharper disable once UseObjectOrCollectionInitializer
                    InteractivePointActive tmp = new InteractivePointActive();

                    tmp.IsActive     = true;
                    tmp.ValueX       = pair.Strike;
                    tmp.ValueY       = sigma;
                    tmp.DragableMode = DragableMode.Yonly;
                    tmp.Tooltip      = String.Format(CultureInfo.InvariantCulture,
                                                     " F: {0}\r\n K: {1}; IV: {2:P2}\r\n {3} px {4}",
                                                     futPx, pair.Strike, sigma, optionType, theorOptPxBitcoins);

                    tmp.Tag = nodeInfo;

                    //tmp.Color = Colors.White;
                    if (m_qty > 0)
                    {
                        tmp.Geometry = Geometries.Triangle;
                    }
                    else if (m_qty < 0)
                    {
                        tmp.Geometry = Geometries.TriangleDown;
                    }
                    else
                    {
                        tmp.Geometry = Geometries.None;
                    }

                    InteractiveObject obj = new InteractiveObject();
                    obj.Anchor = tmp;

                    controlPoints.Add(obj);
                }

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

                // ReSharper disable once UseObjectOrCollectionInitializer
                SmileInfo sInfo = new SmileInfo();
                sInfo.F            = futPx;
                sInfo.dT           = dT;
                sInfo.Expiry       = oldInfo.Expiry;
                sInfo.ScriptTime   = oldInfo.ScriptTime;
                sInfo.RiskFreeRate = oldInfo.RiskFreeRate;
                sInfo.BaseTicker   = oldInfo.BaseTicker;

                res.Tag = sInfo;

                if (controlPoints.Count > 0)
                {
                    res.ClickEvent -= InteractiveSplineOnQuoteIvEvent;
                    res.ClickEvent += InteractiveSplineOnQuoteIvEvent;

                    m_clickableSeries = res;
                }
            }
            #endregion 2. Формируем улыбку просто для отображения текущего положения потенциальной котировки

            PositionsManager posMan = PositionsManager.GetManager(m_context);
            if (m_cancelAllLong)
            {
                posMan.DropAllLongIvTargets(m_context);
            }
            if (m_cancelAllShort)
            {
                posMan.DropAllShortIvTargets(m_context);
            }

            #region 4. Котирование
            {
                var longTargets  = posMan.GetIvTargets(true);
                var shortTargets = posMan.GetIvTargets(false);
                var ivTargets    = longTargets.Union(shortTargets).ToList();
                for (int j = 0; j < ivTargets.Count; j++)
                {
                    var ivTarget = ivTargets[j];

                    // PROD-6102 - Требуется точное совпадение опционной серии
                    if (optSer.ExpirationDate.Date != ivTarget.SecInfo.Expiry.Date)
                    {
                        // Вывести предупреждение???
                        continue;
                    }

                    IOptionStrikePair pair;
                    double            k = ivTarget.SecInfo.Strike;
                    if (!optSer.TryGetStrikePair(k, out pair))
                    {
                        // Вывести предупреждение???
                        continue;
                    }

                    double      sigma;
                    QuoteIvMode quoteMode = ivTarget.QuoteMode;
                    if (quoteMode == QuoteIvMode.Absolute)
                    {
                        sigma = ivTarget.EntryIv;
                    }
                    else
                    {
                        sigma = oldInfo.ContinuousFunction.Value(k) + ivTarget.EntryIv;
                        if (!DoubleUtil.IsPositive(sigma))
                        {
                            //string msg = String.Format("[DEBUG:{0}] Invalid sigma:{1} for strike:{2}", GetType().Name, sigma, nodeInfo.Strike);
                            //m_context.Log(msg, MessageType.Warning, true);
                            continue;
                        }
                    }

                    //bool isCall = (futPx <= pair.Strike);
                    // Определяю тип опциона на основании информации в Задаче
                    StrikeType taskOptionType = StrikeType.Any;
                    if (ivTarget.SecInfo.StrikeType.HasValue)
                    {
                        taskOptionType = ivTarget.SecInfo.StrikeType.Value;
                    }

                    bool isCall;
                    if (taskOptionType == StrikeType.Call)
                    {
                        isCall = true;
                    }
                    else if (taskOptionType == StrikeType.Put)
                    {
                        isCall = false;
                    }
                    else
                    {
                        isCall = (futPx <= pair.Strike); // Это аварийная ситуация?
                    }
                    StrikeType optionType = isCall ? StrikeType.Call : StrikeType.Put;
                    Contract.Assert(pair.Tick < 1, $"#3 На тестовом контуре Дерибит присылает неправильный шаг цены! Tick:{pair.Tick}; Decimals:{pair.Put.Security.Decimals}");
                    double theorOptPxDollars = FinMath.GetOptionPrice(futPx, pair.Strike, dT, sigma, oldInfo.RiskFreeRate, isCall);
                    // Сразу(!!!) переводим котировку из баксов в битки
                    double theorOptPxBitcoins = theorOptPxDollars / scaleMult;

                    // Сдвигаем цену в долларах (с учетом ш.ц. в баксах)
                    theorOptPxDollars += ivTarget.EntryShiftPrice * pair.Tick * scaleMult;
                    theorOptPxDollars  = Math.Round(theorOptPxDollars / (pair.Tick * scaleMult)) * (pair.Tick * scaleMult);

                    // Сдвигаем цену в биткойнах (с учетом ш.ц. в битках)
                    theorOptPxBitcoins += ivTarget.EntryShiftPrice * pair.Tick;
                    theorOptPxBitcoins  = Math.Round(theorOptPxBitcoins / pair.Tick) * pair.Tick;
                    if ((!DoubleUtil.IsPositive(theorOptPxBitcoins)) || (!DoubleUtil.IsPositive(theorOptPxDollars)))
                    {
                        //string msg = String.Format("[DEBUG:{0}] Invalid theorOptPx:{1} for strike:{2}", GetType().Name, theorOptPx, nodeInfo.Strike);
                        //m_context.Log(msg, MessageType.Warning, true);
                        continue;
                    }

                    IOptionStrike optStrike = isCall ? pair.Call : pair.Put;
                    ISecurity     sec       = optStrike.Security;
                    double        totalQty  = posMan.GetTotalQty(sec, m_context.BarsCount, TotalProfitAlgo.AllPositions, ivTarget.IsLong);
                    // Поскольку котирование страйка по волатильности -- это вопрос набора нужного количества СТРЕДДЛОВ,
                    // то учитывать надо суммарный объём опционов как в колах, так и в путах.
                    // НО ЗАДАЧУ-ТО Я СТАВЛЮ ДЛЯ КОНКРЕТНОГО ИНСТРУМЕНТА!
                    // Как быть?
                    //double totalQty = posMan.GetTotalQty(pair.Put.Security, m_context.BarsCount, TotalProfitAlgo.AllPositions, ivTarget.IsLong);
                    //totalQty += posMan.GetTotalQty(pair.Call.Security, m_context.BarsCount, TotalProfitAlgo.AllPositions, ivTarget.IsLong);
                    double targetQty = Math.Abs(ivTarget.TargetShares) - totalQty;
                    // Если имеется дробный LotTick (как в Дерибит к примеру), то надо предварительно округлить
                    targetQty = sec.RoundShares(targetQty);
                    if (targetQty > 0)
                    {
                        string note = String.Format(CultureInfo.InvariantCulture,
                                                    "{0}; ActQty:{1}; Px:{2}; IV:{3:P2}",
                                                    ivTarget.EntryNotes, targetQty, theorOptPxBitcoins, sigma);
                        if (ivTarget.IsLong)
                        {
                            posMan.BuyAtPrice(m_context, sec, targetQty, theorOptPxBitcoins, ivTarget.EntrySignalName, note);
                        }
                        else
                        {
                            posMan.SellAtPrice(m_context, sec, targetQty, theorOptPxBitcoins, ivTarget.EntrySignalName, note);
                        }
                    }
                    else
                    {
                        string msg = String.Format(CultureInfo.InvariantCulture,
                                                   "IvTarget cancelled. SignalName:{0}; Notes:{1}", ivTarget.EntrySignalName, ivTarget.EntryNotes);
                        posMan.CancelVolatility(m_context, ivTarget, msg);

                        // TODO: потом убрать из ГЛ
                        m_context.Log(msg, MessageType.Info, true, new Dictionary <string, object> {
                            { "VOLATILITY_ORDER_CANCELLED", msg }
                        });
                    }
                }
            }
            #endregion 4. Котирование

            #region 5. Торговля
            if (m_executeCommand && (!DoubleUtil.IsZero(m_qty)))
            {
                double k;
                if ((!Double.TryParse(m_strike, out k)) &&
                    (!Double.TryParse(m_strike, NumberStyles.Any, CultureInfo.InvariantCulture, out k)))
                {
                    return(res);
                }

                var pair = (from p in pairs where DoubleUtil.AreClose(k, p.Strike) select p).SingleOrDefault();
                if (pair == null)
                {
                    return(res);
                }

                InteractiveObject obj = (from o in controlPoints where DoubleUtil.AreClose(k, o.Anchor.ValueX) select o).SingleOrDefault();
                if (obj == null)
                {
                    return(res);
                }

                // TODO: для режима котирования в абсолютных числах сделать отдельную ветку
                //double iv = obj.Anchor.ValueY;
                const QuoteIvMode QuoteMode = QuoteIvMode.Relative;
                if (posMan.BlockTrading)
                {
                    string msg = String.Format(RM.GetString("OptHandlerMsg.PositionsManager.TradingBlocked"),
                                               m_context.Runtime.TradeName + ":QuoteIv");
                    m_context.Log(msg, MessageType.Warning, true);
                    return(res);
                }

                // Выбираю тип инструмента пут или колл?
                bool isCall;
                if (m_optionType == StrikeType.Call)
                {
                    isCall = true;
                }
                else if (m_optionType == StrikeType.Put)
                {
                    isCall = false;
                }
                else
                {
                    isCall = (futPx <= k);
                }

                double iv     = m_shiftIv;
                int    shift  = m_shiftPriceStep;
                var    option = isCall ? pair.Call : pair.Put;
                if (m_qty > 0)
                {
                    // Пересчитываю целочисленный параметр Qty в фактические лоты конкретного инструмента
                    double actQty  = m_qty * option.LotTick;
                    string sigName = String.Format(CultureInfo.InvariantCulture,
                                                   "Qty:{0}; IV:{1:P2}+{2}; dT:{3}; Mode:{4}", actQty, iv, shift, dT, QuoteMode);
                    posMan.BuyVolatility(m_context, option, Math.Abs(actQty), QuoteMode, iv, shift, "BuyVola", sigName);

                    m_context.Log(sigName, MessageType.Info, false);
                }
                else if (m_qty < 0)
                {
                    // Пересчитываю целочисленный параметр Qty в фактические лоты конкретного инструмента
                    double actQty  = m_qty * option.LotTick;
                    string sigName = String.Format(CultureInfo.InvariantCulture,
                                                   "Qty:{0}; IV:{1:P2}+{2}; dT:{3}; Mode:{4}", actQty, iv, shift, dT, QuoteMode);
                    posMan.SellVolatility(m_context, option, Math.Abs(actQty), QuoteMode, iv, shift, "SellVola", sigName);

                    m_context.Log(sigName, MessageType.Info, false);
                }
            }
            #endregion 5. Торговля

            return(res);
        }
示例#5
0
        public InteractiveSeries Execute(IOptionSeries optSer, int barNum)
        {
            int barsCount = ContextBarsCount;

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

            int      lastBarIndex   = optSer.UnderlyingAsset.Bars.Count - 1;
            DateTime now            = optSer.UnderlyingAsset.Bars[Math.Min(barNum, lastBarIndex)].Date;
            bool     wasInitialized = HandlerInitializedToday(now);

            IOptionStrike[]  options = optSer.GetStrikes().ToArray();
            PositionsManager posMan  = PositionsManager.GetManager(m_context);

            //if (Context.Runtime.IsAgentMode)
            //{
            // PROD-6089 - Если мы в режиме агента, значит все инструменты уже ISecurityRt
            //    SortedList<DateTime, IOrder> sortedOrders = new SortedList<DateTime, IOrder>(s_comparer);
            //}

            SortedList <DateTime, IPosition> sortedPos = new SortedList <DateTime, IPosition>(s_comparer);

            if (m_countFutures)
            {
                ReadOnlyCollection <IPosition> futPositions = posMan.GetActiveForBar(optSer.UnderlyingAsset);
                if (futPositions.Count > 0)
                {
                    for (int j = 0; j < futPositions.Count; j++)
                    {
                        IPosition pos = futPositions[j];
                        AddSafely(sortedPos, pos);
                    }
                }
            }

            for (int m = 0; m < options.Length; m++)
            {
                IOptionStrike optStrike = options[m];
                ReadOnlyCollection <IPosition> optPositions = posMan.GetActiveForBar(optStrike.Security);
                if (optPositions.Count > 0)
                {
                    for (int j = 0; j < optPositions.Count; j++)
                    {
                        IPosition pos = optPositions[j];
                        AddSafely(sortedPos, pos);
                    }
                }
            }

            int counter = 0;
            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            foreach (var node in sortedPos)
            {
                InteractivePointActive ip = new InteractivePointActive();
                ip.IsActive = true;
                //ip.DragableMode = DragableMode.None;
                ip.DateTime = node.Key;
                ip.ValueX   = 0; // все одинаковые 'страйки' имеют
                ip.ValueY   = PrepareValue(node, barNum, m_displayMode);
                ip.Tooltip  = PrepareTooltip(node, barNum, m_displayMode);

                controlPoints.Add(new InteractiveObject(ip));

                counter++;
                if (counter >= m_maxPositions)
                {
                    break;
                }
            }

            InteractiveSeries res = new InteractiveSeries(); // Здесь правильно делать new

            // Задаю свойство для отображения
            switch (m_displayMode)
            {
            case PositionGridDisplayMode.Px:
            case PositionGridDisplayMode.Qty:
                res.DisplayProperty.Name = nameof(IInteractivePointLight.ValueY);
                break;

            default:
                res.DisplayProperty.Name = nameof(InteractivePointActive.Tooltip);
                break;
            }
            res.ControlPoints = new ReadOnlyCollection <InteractiveObject>(controlPoints);

            SetHandlerInitialized(now);

            return(res);
        }
示例#6
0
        public Double2N Execute(IOptionStrike source)
        {
            var strikes = source != null ? new[] { source } : new IOptionStrike[0];

            return(CalculateInternal(strikes));
        }
示例#7
0
 protected abstract void FillStrikeInfo(IOptionStrike optionStrike, StrikeInfo stInfo);
示例#8
0
        /// <summary>
        /// Вычисление цены опциона различными способами. Есть возможность сразу сделать сдвиг цены (предусмотрены проверки).
        /// </summary>
        /// <param name="externalContext">Контекст блока для логгирования проблемы</param>
        /// <param name="f">Цена БА (нажна как верхняя оценка цены колла</param>
        /// <param name="sec">Инструмент</param>
        /// <param name="mode">алгоритм расчета (покупка, продажа, середина спреда)</param>
        /// <param name="shiftAsk">сдвиг асков</param>
        /// <param name="shiftBid">сдвиг бидов</param>
        /// <param name="qty">количество лотов в заявке</param>
        /// <param name="optTime">время получения этих котировок из рыночного провайдера</param>
        /// <returns>цена опциона (в случае проблем возвращает NaN)</returns>
        public static double GetOptPrice(IContext externalContext, double f, IOptionStrike sec, OptionPxMode mode,
                                         double shiftAsk, double shiftBid, out double qty, out DateTime optTime)
        {
            qty     = Double.NaN;
            optTime = new DateTime();
            double optPx = Double.NaN;

            // PROD-5952 - Не надо дергать стакан без нужды
            //sec.UpdateQueueData();
            if (mode == OptionPxMode.Ask)
            {
                if (/* sec.FinInfo.AskSize.HasValue && */ sec.FinInfo.Ask.HasValue)
                {
                    optPx   = sec.FinInfo.Ask.Value;
                    optTime = sec.FinInfo.LastUpdate;

                    qty = 0;
                    if (sec.FinInfo.AskSize.HasValue)
                    {
                        qty = sec.FinInfo.AskSize.Value;
                    }
                    else
                    {
                        // PROD-5952 - Не надо дергать стакан без нужды
                        //// Аски отсортированы по возрастанию
                        //var queue = sec.GetSellQueue(externalContext.BarsCount - 1);
                        //if ((queue != null) && (queue.Count > 0))
                        //{
                        //    IQueueData ask = queue[0]; // queue.First();
                        //    qty = ask.Quantity;
                        //}
                    }
                }
                else
                {
                    // PROD-5952 - Не надо дергать стакан без нужды
                    #region Нет данных в FinInfo
//                    // Аски отсортированы по возрастанию
//                    var queue = sec.GetSellQueue(externalContext.BarsCount - 1);
//                    if ((queue != null) && (queue.Count > 0))
//                    {
//                        IQueueData ask = queue[0]; // queue.First();

//#if DEBUG
//                        if (!s_conflictDate.ContainsKey(sec.Security.SecurityDescription.FullName))
//                        {
//                            bool check = (ask.Security.FullName == sec.Security.SecurityDescription.FullName);
//                            if (!check)
//                                s_conflictDate[sec.Security.SecurityDescription.FullName] = ask.LastUpdate;

//                            Debug.Assert(check,
//                                String.Format("Expected security: {0}; actual security: {1}",
//                                    sec.Security.SecurityDescription.FullName, ask.Security.FullName));
//                        }
//#endif

//                        optPx = ask.Price;
//                        qty = ask.Quantity;
//                        optTime = ask.LastUpdate;

//                        //string msg =
//                        //    String.Format(
//                        //        "[DEBUG:{0}] I was forced to use 'sec.GetSellQueue'. sec.Bars.Count:{1}; ask.LastUpdate:{2}; sec:{3}",
//                        //        typeof(IvSmile).Name, sec.Bars.Count,
//                        //        ask.LastUpdate.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture),
//                        //        sec);
//                        //externalContext.Log(msg, MessageType.Warning, true);
//                    }
                    #endregion Нет данных в FinInfo
                }

                if (Double.IsNaN(optPx) || (optPx <= Double.Epsilon))
                {
                    optPx = 2 * f; // Это одна из верхних оценок цены опциона.
                }
                else
                {
                    optPx += shiftAsk;
                }
            }
            else if (mode == OptionPxMode.Bid)
            {
                if (/* sec.FinInfo.BidSize.HasValue && */ sec.FinInfo.Bid.HasValue)
                {
                    optPx   = sec.FinInfo.Bid.Value;
                    optTime = sec.FinInfo.LastUpdate;

                    qty = 0;
                    if (sec.FinInfo.BidSize.HasValue)
                    {
                        qty = sec.FinInfo.BidSize.Value;
                    }
                    else
                    {
                        // PROD-5952 - Не надо дергать стакан без нужды
                        //// Биды отсортированы ПО УБЫВАНИЮ!!!
                        //var queue = sec.GetBuyQueue(externalContext.BarsCount - 1);
                        //if ((queue != null) && (queue.Count > 0))
                        //{
                        //    IQueueData bid = queue[0]; // queue.First();
                        //    qty = bid.Quantity;
                        //}
                    }
                }
                else
                {
                    // PROD-5952 - Не надо дергать стакан без нужды
                    #region Нет данных в FinInfo
//                    // Биды отсортированы ПО УБЫВАНИЮ!!!
//                    var queue = sec.GetBuyQueue(externalContext.BarsCount - 1);
//                    if ((queue != null) && (queue.Count > 0))
//                    {
//                        IQueueData bid = queue[0]; // queue.First();

//#if DEBUG
//                        if (!s_conflictDate.ContainsKey(sec.Security.SecurityDescription.FullName))
//                        {
//                            bool check = (bid.Security.FullName == sec.Security.SecurityDescription.FullName);
//                            if (!check)
//                                s_conflictDate[sec.Security.SecurityDescription.FullName] = bid.LastUpdate;

//                            Debug.Assert(check,
//                                String.Format("Expected security: {0}; actual security: {1}",
//                                    sec.Security.SecurityDescription.FullName, bid.Security.FullName));
//                        }
//#endif

//                        optPx = bid.Price;
//                        qty = bid.Quantity;
//                        optPx -= shiftBid;
//                        optPx = Math.Max(optPx, 0);

//                        optTime = bid.LastUpdate;

//                        //string msg =
//                        //    String.Format(
//                        //        "[DEBUG:{0}] I was forced to use 'sec.GetSellQueue'. sec.Bars.Count:{1}; bid.LastUpdate:{2}; sec:{3}",
//                        //        typeof(IvSmile).Name, sec.Bars.Count,
//                        //        bid.LastUpdate.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture),
//                        //        sec);
//                        //externalContext.Log(msg, MessageType.Warning, true);
//                    }
                    #endregion Нет данных в FinInfo
                }
            }
            else if (mode == OptionPxMode.Mid)
            {
                if (/* sec.FinInfo.BidSize.HasValue && */ sec.FinInfo.Bid.HasValue &&
                    /* sec.FinInfo.AskSize.HasValue && */ sec.FinInfo.Ask.HasValue)
                {
                    double askPx = sec.FinInfo.Ask.Value;
                    //double askQty = sec.FinInfo.AskSize.Value;
                    if (Double.IsNaN(askPx) || (askPx <= Double.Epsilon))
                    {
                        askPx = 2.0 * f; // Это одна из верхних оценок цены опциона.
                    }
                    else
                    {
                        askPx += shiftAsk;
                    }

                    double bidPx = sec.FinInfo.Bid.Value;
                    //double bidQty = sec.FinInfo.BidSize.Value;
                    bidPx -= shiftBid;
                    bidPx  = Math.Max(bidPx, 0);

                    optPx = (askPx + bidPx) / 2.0;
                    //qty = Math.Min(askQty, bidQty);

                    double askQty = 0, bidQty = 0;
                    #region AskQty
                    if (sec.FinInfo.AskSize.HasValue)
                    {
                        askQty = sec.FinInfo.AskSize.Value;
                    }
                    else
                    {
                        // PROD-5952 - Не надо дергать стакан без нужды
                        //// Аски отсортированы по возрастанию
                        //var queue = sec.GetSellQueue(externalContext.BarsCount - 1);
                        //if ((queue != null) && (queue.Count > 0))
                        //{
                        //    IQueueData ask = queue[0]; // queue.First();
                        //    askQty = ask.Quantity;
                        //}
                    }
                    #endregion AskQty

                    #region BidQty
                    if (sec.FinInfo.BidSize.HasValue)
                    {
                        bidQty = sec.FinInfo.BidSize.Value;
                    }
                    else
                    {
                        // PROD-5952 - Не надо дергать стакан без нужды
                        //// Биды отсортированы ПО УБЫВАНИЮ!!!
                        //var queue = sec.GetBuyQueue(externalContext.BarsCount - 1);
                        //if ((queue != null) && (queue.Count > 0))
                        //{
                        //    IQueueData bid = queue[0]; // queue.First();
                        //    bidQty = bid.Quantity;
                        //}
                    }
                    #endregion BidQty

                    qty = Math.Min(askQty, bidQty);

                    optTime = sec.FinInfo.LastUpdate;
                }
                else
                {
                    // PROD-5952 - Не надо дергать стакан без нужды
                    #region Нет данных в FinInfo
//                    var askQueue = sec.GetSellQueue(externalContext.BarsCount - 1);
//                    var bidQueue = sec.GetBuyQueue(externalContext.BarsCount - 1);
//                    if ((askQueue != null) && (askQueue.Count > 0) &&
//                        (bidQueue != null) && (bidQueue.Count > 0))
//                    {
//                        // Аски отсортированы по возрастанию
//                        IQueueData ask = askQueue[0]; // askQueue.First();

//#if DEBUG
//                        if (!s_conflictDate.ContainsKey(sec.Security.SecurityDescription.FullName))
//                        {
//                            bool check = (ask.Security.FullName == sec.Security.SecurityDescription.FullName);
//                            if (!check)
//                                s_conflictDate[sec.Security.SecurityDescription.FullName] = ask.LastUpdate;

//                            Debug.Assert(check,
//                                String.Format("Expected security: {0}; actual security: {1}",
//                                    sec.Security.SecurityDescription.FullName, ask.Security.FullName));
//                        }
//#endif

//                        double askPx = ask.Price;
//                        double askQty = ask.Quantity;
//                        if (Double.IsNaN(askPx) || (askPx <= Double.Epsilon))
//                            askPx = 2.0 * f; // Это одна из верхних оценок цены опциона.
//                        else
//                            askPx += shiftAsk;

//                        // Биды отсортированы ПО УБЫВАНИЮ!!!
//                        IQueueData bid = bidQueue[0]; // bidQueue.First();

//#if DEBUG
//                        if (!s_conflictDate.ContainsKey(sec.Security.SecurityDescription.FullName))
//                        {
//                            bool check = (bid.Security.FullName == sec.Security.SecurityDescription.FullName);
//                            if (!check)
//                                s_conflictDate[sec.Security.SecurityDescription.FullName] = bid.LastUpdate;

//                            Debug.Assert(check,
//                                String.Format("Expected security: {0}; actual security: {1}",
//                                    sec.Security.SecurityDescription.FullName, bid.Security.FullName));
//                        }
//#endif

//                        double bidPx = bid.Price;
//                        double bidQty = bid.Quantity;
//                        bidPx -= shiftBid;
//                        bidPx = Math.Max(bidPx, 0);

//                        optPx = (askPx + bidPx) / 2.0;
//                        qty = Math.Min(askQty, bidQty);

//                        optTime = (bid.LastUpdate < ask.LastUpdate) ? ask.LastUpdate : bid.LastUpdate;
//                    }
                    #endregion Нет данных в FinInfo
                }
            }
            else
            {
                throw new NotImplementedException("OptPxMode:" + mode);
            }

            return(optPx);
        }
示例#9
0
            public bool Equals(IOptionStrike optionStrike)
            {
                bool res = Equals(optionStrike.FinInfo.Security);

                return(res);
            }