Esempio n. 1
0
        internal static void FillNodeInfoDeribit(InteractivePointActive ip,
                                                 double f, double dT, IOptionStrikePair sInfo,
                                                 StrikeType optionType, OptionPxMode optPxMode,
                                                 double optPx, double optQty, double optSigma, DateTime optTime, bool returnPct, double riskfreeRatePct, double scaleMult)
        {
            // Вызов базовой реализации
            FillNodeInfo(ip, f, dT, sInfo, optionType, optPxMode, optPx, optQty, optSigma, optTime, returnPct, riskfreeRatePct);

            // Заменяю тултип, чтобы в нем были и биткойны и доллары
            var opTypeStr   = String.Intern(optionType.ToString());
            var opTypeSpace = String.Intern(new string(' ', opTypeStr.Length));

            // Пробелы по виду занимают меньше места, чем буквы, поэтому чуть-чуть подравниваю?
            opTypeSpace += "  ";
            if (optQty > 0)
            {
                ip.Tooltip = String.Format(CultureInfo.InvariantCulture,
                                           " K:{0}; IV:{1:###0.00}%\r\n" +
                                           " {2} px(B) {3:##0.0000} qty {4}\r\n" +
                                           " {5} px($) {6:######0.00} qty {4}",
                                           sInfo.Strike, optSigma * Constants.PctMult, opTypeStr, optPx, optQty,
                                           opTypeSpace, optPx * scaleMult);
            }
            else
            {
                ip.Tooltip = String.Format(CultureInfo.InvariantCulture,
                                           " K:{0}; IV:{1:###0.00}%\r\n" +
                                           " {2} px(B) {3:##0.0000}\r\n" +
                                           " {4} px($) {5:######0.00}",
                                           sInfo.Strike, optSigma * Constants.PctMult, opTypeStr, optPx,
                                           opTypeSpace, optPx * scaleMult);
            }
        }
Esempio n. 2
0
        public InteractiveSeries Execute(ISecurity security)
        {
            var interactiveObjects = new List <InteractiveObject>();

            for (byte i = 0; i < 31; i++)
            {
                var j = (byte)(i << 3);
                var interactivePointActive = new InteractivePointActive(i, i)
                {
                    BackColor = new Color(j, 0, 0),
                    ForeColor = new Color(0, j, 0),

                    IsActive = true,
                    Label    = i.ToString(),
                    Color    = new AlphaColor(255, j, 0, 0),
                    DateTime = DateTime.UtcNow.AddDays(1),

                    ValueXBackColor = new AlphaColor(255, j, 0, 0),
                    ValueXForeColor = new AlphaColor(255, 0, j, 0),

                    ValueYBackColor = new AlphaColor(255, 0, j, 0),
                    ValueYForeColor = new AlphaColor(255, 0, 0, j),

                    DateTimeBackColor = new AlphaColor(255, 0, 0, j),
                    DateTimeForeColor = new AlphaColor(255, j, 0, 0),
                };
                interactiveObjects.Add(new InteractiveObject {
                    Anchor = interactivePointActive
                });
            }
            return(new InteractiveSeries(interactiveObjects));
        }
        internal static void FillNodeInfo(InteractivePointActive ip,
                                          double f, double dT, IOptionStrikePair sInfo,
                                          StrikeType optionType, OptionPxMode optPxMode,
                                          double optSigma, bool returnPct, bool isVisiblePoints, double scaleMult, double riskfreeRatePct)
        {
            if (optionType == StrikeType.Any)
            {
                throw new ArgumentException("Option type 'Any' is not supported.", "optionType");
            }

            bool   isCall = (optionType == StrikeType.Call);
            double optPx  = FinMath.GetOptionPrice(f, sInfo.Strike, dT, optSigma, 0, isCall);

            // Сразу переводим котировку из баксов в битки
            optPx /= scaleMult;

            // ReSharper disable once UseObjectOrCollectionInitializer
            SmileNodeInfo nodeInfo = new SmileNodeInfo();

            nodeInfo.F            = f;
            nodeInfo.dT           = dT;
            nodeInfo.RiskFreeRate = riskfreeRatePct;
            nodeInfo.Sigma        = returnPct ? optSigma * Constants.PctMult : optSigma;
            nodeInfo.OptPx        = optPx;
            nodeInfo.Strike       = sInfo.Strike;
            // Сюда мы приходим когда хотим торговать, поэтому обращение к Security уместно
            nodeInfo.Security   = (optionType == StrikeType.Put) ? sInfo.Put.Security : sInfo.Call.Security;
            nodeInfo.PxMode     = optPxMode;
            nodeInfo.OptionType = optionType;
            nodeInfo.Pair       = sInfo;
            //nodeInfo.ScriptTime = optTime;
            nodeInfo.CalendarTime = DateTime.Now;

            nodeInfo.Symbol   = nodeInfo.Security.Symbol;
            nodeInfo.DSName   = nodeInfo.Security.SecurityDescription.DSName;
            nodeInfo.Expired  = nodeInfo.Security.SecurityDescription.Expired;
            nodeInfo.FullName = nodeInfo.Security.SecurityDescription.FullName;

            ip.Tag = nodeInfo;
            //ip.Color = Colors.Yellow;
            ip.IsActive     = isVisiblePoints;
            ip.Geometry     = Geometries.Ellipse;
            ip.DragableMode = DragableMode.None;
            //ip.Value = new System.Windows.Point(sInfo.Strike, nodeInfo.Sigma);
            // Поскольку цены скорее всего расчетные, показываю на 1 знак болььше, чем объявлена точность в инструменте
            int    decim    = Math.Max(0, nodeInfo.Security.Decimals + 1);
            string optPxStr = optPx.ToString("N" + decim, CultureInfo.InvariantCulture);

            ip.Tooltip = String.Format(CultureInfo.InvariantCulture,
                                       " K: {0}; IV: {1:#0.00}%\r\n   {2} px {3}",
                                       sInfo.Strike, optSigma * Constants.PctMult, optionType, optPx);
        }
        public InteractiveSeries Execute(InteractiveSeries ser1, InteractiveSeries ser2, int barNum)
        {
            int barsCount = m_context.BarsCount;

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

            if ((ser1 == null) && (ser2 == null))
            {
                return(Constants.EmptySeries);
            }
            else if ((ser1 == null) && (ser2 != null))
            {
                return(ser2);
            }
            else if ((ser1 != null) && (ser2 == null))
            {
                return(ser1);
            }

            var query = (from s1 in ser1.ControlPoints
                         from s2 in ser2.ControlPoints
                         where DoubleUtil.AreClose(s1.Anchor.Value.X, s2.Anchor.Value.X)
                         select new { cp1 = s1, cp2 = s2 });

            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            foreach (var pair in query)
            {
                double x = pair.cp1.Anchor.Value.X;
                double y = pair.cp1.Anchor.Value.Y + pair.cp2.Anchor.Value.Y;
                InteractivePointActive ip = new InteractivePointActive(x, y);
                //ip.Geometry = Geometries.Rect;
                ip.Tooltip = String.Format("F:{0}; PnL:{1}", x, y);

                controlPoints.Add(new InteractiveObject(ip));
            }

            InteractiveSeries res = new InteractiveSeries(); // Здесь так надо -- мы делаем новую улыбку

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

            return(res);
        }
Esempio n. 5
0
        private void InteractiveSplineOnClickEvent(object sender, InteractiveActionEventArgs eventArgs)
        {
            OptionPxMode pxMode = m_isLong ? OptionPxMode.Ask : OptionPxMode.Bid;

            PositionsManager posMan = PositionsManager.GetManager(m_context);
            // Из практики торговли часто бывает ситуация, что торговля заблокирована, а снять задачу котирования УЖЕ хочется.
            //if (posMan.BlockTrading)
            //{
            //    //string msg = String.Format("[{0}] Trading is blocked. Please, change 'Block Trading' parameter.", m_optionPxMode);
            //    string msg = String.Format(RM.GetString("OptHandlerMsg.PositionsManager.TradingBlocked"), pxMode);
            //    m_context.Log(msg, MessageType.Info, true);
            //    return;
            //}

            InteractivePointActive tmp = eventArgs.Point;

            if ((tmp.Tag == null) || (!(tmp.Tag is PositionsManager.IvTargetInfo)))
            {
                string msg = String.Format("[{0}.ClickEvent] Denied #1", GetType().Name);
                m_context.Log(msg, MessageType.Warning, false);
                return;
            }

            {
                string msg = String.Format(CultureInfo.InvariantCulture, "[{0}.ClickEvent] Strike: {1}", GetType().Name, eventArgs.Point.ValueX);
                m_context.Log(msg, MessageType.Warning, false);
            }

            var ivTarget = tmp.Tag as PositionsManager.IvTargetInfo;

            // Передаю событие в PositionsManager
            //posMan.InteractiveSplineOnQuoteIvEvent(m_context, sender, eventArgs);
            // ОЧЕНЬ БОЛЬШОЙ ВОПРОС ЧТО БУДЕТ С КОНТЕКСТОМ ПРИ ЭТОМ???
            int res = posMan.CancelVolatility(m_context, ivTarget, "Left-click");

            if (res > 0)
            {
                string msg = String.Format(RM.GetString("OptHandlerMsg.PositionsManager.IvTargetCancelled"), pxMode, ivTarget);
                m_context.Log(msg, MessageType.Info, true, new Dictionary <string, object> {
                    { "VOLATILITY_ORDER_CANCELLED", msg }
                });

                // Вызываем принудительный пересчет агента, чтобы немедленно убрать заявку из стакана
                m_context.Recalc();
            }
        }
Esempio n. 6
0
        internal static void FillNodeInfo(InteractivePointActive ip,
                                          double f, double dT, IOptionStrikePair sInfo,
                                          StrikeType optionType, OptionPxMode optPxMode,
                                          double optSigma, bool returnPct, bool isVisiblePoints, double riskfreeRatePct)
        {
            if (optionType == StrikeType.Any)
            {
                throw new ArgumentException("Option type 'Any' is not supported.", "optionType");
            }

            bool   isCall = (optionType == StrikeType.Call);
            double optPx  = FinMath.GetOptionPrice(f, sInfo.Strike, dT, optSigma, 0, isCall);

            // ReSharper disable once UseObjectOrCollectionInitializer
            SmileNodeInfo nodeInfo = new SmileNodeInfo();

            nodeInfo.F            = f;
            nodeInfo.dT           = dT;
            nodeInfo.RiskFreeRate = riskfreeRatePct;
            nodeInfo.Sigma        = returnPct ? optSigma * Constants.PctMult : optSigma;
            nodeInfo.OptPx        = optPx;
            nodeInfo.Strike       = sInfo.Strike;
            // Сюда мы приходим когда хотим торговать, поэтому обращение к Security уместно
            nodeInfo.Security   = (optionType == StrikeType.Put) ? sInfo.Put.Security : sInfo.Call.Security;
            nodeInfo.PxMode     = optPxMode;
            nodeInfo.OptionType = optionType;
            nodeInfo.Pair       = sInfo;
            //nodeInfo.ScriptTime = optTime;
            nodeInfo.CalendarTime = DateTime.Now;

            nodeInfo.Symbol   = nodeInfo.Security.Symbol;
            nodeInfo.DSName   = nodeInfo.Security.SecurityDescription.DSName;
            nodeInfo.Expired  = nodeInfo.Security.SecurityDescription.Expired;
            nodeInfo.FullName = nodeInfo.Security.SecurityDescription.FullName;

            ip.Tag          = nodeInfo;
            ip.Color        = AlphaColors.Yellow;
            ip.IsActive     = isVisiblePoints;
            ip.Geometry     = Geometries.Ellipse;
            ip.DragableMode = DragableMode.None;
            //ip.Value = new System.Windows.Point(sInfo.Strike, nodeInfo.Sigma);
            ip.Tooltip = String.Format(CultureInfo.InvariantCulture,
                                       "F:{0}; K:{1}; IV:{2:#0.00}%\r\n{3} px {4}",
                                       f, sInfo.Strike, optSigma * Constants.PctMult, optionType, optPx);
        }
Esempio n. 7
0
        protected static void FillNodeInfo(InteractivePointLight ip,
                                           double f, double dT, IOptionStrikePair sInfo,
                                           StrikeType optionType, OptionPxMode optPxMode,
                                           double optSigma, bool returnPct, double pctRate)
        {
            if (optionType == StrikeType.Any)
            {
                throw new ArgumentException("Option type 'Any' is not supported.", "optionType");
            }

            bool   isCall = (optionType == StrikeType.Call);
            double optPx  = FinMath.GetOptionPrice(f, sInfo.Strike, dT, optSigma, pctRate, isCall);

            // ReSharper disable once UseObjectOrCollectionInitializer
            SmileNodeInfo nodeInfo = new SmileNodeInfo();

            nodeInfo.F            = f;
            nodeInfo.dT           = dT;
            nodeInfo.RiskFreeRate = pctRate;
            nodeInfo.Sigma        = returnPct ? optSigma * Constants.PctMult : optSigma;
            nodeInfo.OptPx        = optPx;
            nodeInfo.Strike       = sInfo.Strike;
            nodeInfo.Security     = (optionType == StrikeType.Put) ? sInfo.Put.Security : sInfo.Call.Security;
            nodeInfo.PxMode       = optPxMode;
            nodeInfo.OptionType   = optionType;
            nodeInfo.Pair         = sInfo;
            //nodeInfo.ScriptTime = optTime;
            nodeInfo.CalendarTime = DateTime.Now;

            nodeInfo.Symbol   = nodeInfo.Security.Symbol;
            nodeInfo.DSName   = nodeInfo.Security.SecurityDescription.DSName;
            nodeInfo.FullName = nodeInfo.Security.SecurityDescription.FullName;
            nodeInfo.Expired  = nodeInfo.Security.SecurityDescription.Expired;

            ip.Tag   = nodeInfo;
            ip.Value = new Point(sInfo.Strike, nodeInfo.Sigma);

            if (ip is InteractivePointActive)
            {
                InteractivePointActive ipa = (InteractivePointActive)ip;
                ipa.Tooltip = String.Format("K:{0}; IV:{1:#0.00}%\r\n{2} {3} @ {4}",
                                            sInfo.Strike, optSigma * Constants.PctMult, optionType, optPx, DefaultOptQty);
            }
        }
Esempio n. 8
0
        protected static void FillNodeInfo(InteractivePointActive ip,
                                           double f, double dT, IOptionStrikePair sInfo,
                                           StrikeType optionType, OptionPxMode optPxMode,
                                           double optSigma, bool returnPct, bool isVisiblePoints)
        {
            if (optionType == StrikeType.Any)
            {
                throw new ArgumentException("Option type 'Any' is not supported.", "optionType");
            }

            bool   isCall = (optionType == StrikeType.Call);
            double optPx  = FinMath.GetOptionPrice(f, sInfo.Strike, dT, optSigma, 0, isCall);

            SmileNodeInfo nodeInfo = new SmileNodeInfo();

            nodeInfo.F          = f;
            nodeInfo.dT         = dT;
            nodeInfo.Sigma      = returnPct ? optSigma * Constants.PctMult : optSigma;
            nodeInfo.OptPx      = optPx;
            nodeInfo.Strike     = sInfo.Strike;
            nodeInfo.Security   = (optionType == StrikeType.Put) ? sInfo.Put.Security : sInfo.Call.Security;
            nodeInfo.PxMode     = optPxMode;
            nodeInfo.OptionType = optionType;
            nodeInfo.Pair       = sInfo;
            //nodeInfo.ScriptTime = optTime;
            nodeInfo.CalendarTime = DateTime.Now;

            nodeInfo.Symbol  = nodeInfo.Security.Symbol;
            nodeInfo.Expired = nodeInfo.Security.SecurityDescription.Expired;

            ip.Tag          = nodeInfo;
            ip.Color        = AlphaColors.Yellow;
            ip.IsActive     = isVisiblePoints;
            ip.Geometry     = Geometries.Ellipse;
            ip.DragableMode = DragableMode.None;
            //ip.Value = new System.Windows.Point(sInfo.Strike, nodeInfo.Sigma);
            ip.Tooltip = String.Format("F:{0}; K:{1}; IV:{2:#0.00}%\r\n{3} {4} @ {5}",
                                       f, sInfo.Strike, optSigma * Constants.PctMult, optionType, optPx, DefaultOptQty);
        }
Esempio n. 9
0
        /// <summary>
        /// Обработчик под тип входных данных INTERACTIVESPLINE
        /// </summary>
        /// <param name="price">цена БА</param>
        /// <param name="time">время до экспирации в долях года</param>
        /// <param name="optPrices">опционные цены</param>
        /// <param name="rate">процентная ставка</param>
        /// <param name="barNum">индекс бара в серии</param>
        /// <returns>улыбка, восстановленная из цен опционов</returns>
        public InteractiveSeries Execute(double price, double time, InteractiveSeries optPrices, double scaleMult, double rate, int barNum)
        {
            int barsCount = ContextBarsCount;

            if ((barNum < barsCount - 1) || (optPrices == null) || (optPrices.ControlPoints.Count <= 0))
            {
                return(Constants.EmptySeries);
            }

            IReadOnlyList <InteractiveObject> cps = optPrices.ControlPoints;

            double f  = price;
            double dT = time;

            if (!DoubleUtil.IsPositive(f))
            {
                //throw new ScriptException("Argument 'price' contains NaN for some strange reason. f:" + f);
                return(Constants.EmptySeries);
            }
            if (!DoubleUtil.IsPositive(scaleMult))
            {
                //throw new ScriptException("Argument 'scaleMult' contains NaN for some strange reason. scaleMult:" + scaleMult);
                return(Constants.EmptySeries);
            }
            if (!DoubleUtil.IsPositive(dT))
            {
                return(Constants.EmptySeries);
            }
            if (Double.IsNaN(rate))
            {
                //throw new ScriptException("Argument 'rate' contains NaN for some strange reason. rate:" + rate);
                return(Constants.EmptySeries);
            }

            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            for (int j = 0; j < cps.Count; j++)
            {
                InteractiveObject strikeObj = cps[j];
                double            strike    = strikeObj.Anchor.ValueX;
                // Сверхдалекие страйки игнорируем
                if ((strike < m_minStrike) || (m_maxStrike < strike))
                {
                    continue;
                }

                double optPx;
                double stradlePx = Double.NaN;
                double putPx = Double.NaN, callPx = Double.NaN;
                if (m_optionType == StrikeType.Put)
                {
                    putPx = strikeObj.Anchor.ValueY;
                    optPx = putPx;
                    // Здесь нельзя сразу домножать на scaleMultiplier! Потому что тогда в метод FillNodeInfo пойдут бредовые цены.
                }
                else if (m_optionType == StrikeType.Call)
                {
                    callPx = strikeObj.Anchor.ValueY;
                    optPx  = callPx;
                    // Здесь нельзя сразу домножать на scaleMultiplier! Потому что тогда в метод FillNodeInfo пойдут бредовые цены.
                }
                else
                {
                    stradlePx = strikeObj.Anchor.ValueY;
                    optPx     = stradlePx;
                    // Здесь нельзя сразу домножать на scaleMultiplier! Потому что тогда в метод FillNodeInfo пойдут бредовые цены.
                }

                double sigma = Double.NaN;
                double putSigma = Double.NaN, callSigma = Double.NaN, stradleSigma = Double.NaN, precision;
                if (DoubleUtil.IsPositive(putPx))
                {
                    // Цену опциона переводим в баксы только в момент вычисления айви
                    putSigma = FinMath.GetOptionSigma(f, strike, dT, putPx * scaleMult, rate, false, out precision);
                    putSigma = Math.Min(putSigma, m_maxSigma);
                    if (putSigma <= 0)
                    {
                        putSigma = Double.NaN;
                    }
                    else
                    {
                        if (m_optionType == StrikeType.Put)
                        {
                            sigma = putSigma;
                        }
                    }
                }
                if (DoubleUtil.IsPositive(callPx))
                {
                    // Цену опциона переводим в баксы только в момент вычисления айви
                    callSigma = FinMath.GetOptionSigma(f, strike, dT, callPx * scaleMult, rate, true, out precision);
                    callSigma = Math.Min(callSigma, m_maxSigma);
                    if (callSigma <= 0)
                    {
                        callSigma = Double.NaN;
                    }
                    else
                    {
                        if (m_optionType == StrikeType.Call)
                        {
                            sigma = callSigma;
                        }
                    }
                }
                if (DoubleUtil.IsPositive(stradlePx))
                {
                    // Цену опциона переводим в баксы только в момент вычисления айви
                    stradleSigma = FinMath.GetStradleSigma(f, strike, dT, stradlePx * scaleMult, rate, out precision);
                    stradleSigma = Math.Min(stradleSigma, m_maxSigma);
                    if (stradleSigma <= 0)
                    {
                        stradleSigma = Double.NaN;
                    }
                    else
                    {
                        if (m_optionType == StrikeType.Any)
                        {
                            sigma = stradleSigma;
                        }
                    }
                }

                if (Double.IsNaN(sigma) || (sigma <= 0) ||
                    Double.IsNaN(optPx) || (optPx <= 0))
                {
                    continue;
                }

                InteractivePointActive ip = new InteractivePointActive();
                {
                    //ip.Color = (m_optionPxMode == OptionPxMode.Ask) ? Colors.DarkOrange : Colors.DarkCyan;
                    //ip.DragableMode = DragableMode.None;
                    //ip.Geometry = Geometries.Rect; // (optionPxMode == OptionPxMode.Ask) ? Geometries.Rect : Geometries.Rect;
                    //ip.IsActive = true;
                    ip.Value = new Point(strike, sigma);
                    string nowStr = DateTime.Now.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture);
                    ip.Tooltip = String.Format(CultureInfo.InvariantCulture, "K:{0}; IV:{1:#0.00}%\r\n{2} {3} @ {4}\r\nDate: {5}",
                                               strike, sigma * Constants.PctMult, m_optionType, optPx, 1, nowStr);
                }

                InteractiveObject obj = new InteractiveObject(ip);

                if (m_optionType == StrikeType.Put)
                {
                    if (!Double.IsNaN(putSigma))
                    {
                        //FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Put, m_optionPxMode, putPx, putQty, putSigma, putTime, false);
                        controlPoints.Add(obj);
                    }
                }
                else if (m_optionType == StrikeType.Call)
                {
                    if (!Double.IsNaN(callSigma))
                    {
                        //FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Call, m_optionPxMode, callPx, callQty, callSigma, callTime, false);
                        controlPoints.Add(obj);
                    }
                }
                else if (m_optionType == StrikeType.Any)
                {
                    if (!Double.IsNaN(stradleSigma))
                    {
                        if (m_optionPxMode == OptionPxMode.Ask)
                        {
                            //if (putSigma < callSigma)
                            //    FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Put, m_optionPxMode, putPx, putQty, putSigma, putTime, false);
                            //else
                            //    FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Call, m_optionPxMode, callPx, callQty, callSigma, callTime, false);
                        }
                        else if (m_optionPxMode == OptionPxMode.Bid)
                        {
                            //if (putSigma > callSigma)
                            //    FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Put, m_optionPxMode, putPx, putQty, putSigma, putTime, false);
                            //else
                            //    FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Call, m_optionPxMode, callPx, callQty, callSigma, callTime, false);
                        }

                        controlPoints.Add(obj);
                    }
                }
            }

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

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

            SmileInfo info;

            if (!IvSmile.TryPrepareSmileInfo(m_context, f, dT, rate, new DateTime(), new DateTime(), null, res, out info))
            {
                return(Constants.EmptySeries);
            }

            return(res);
        }
Esempio n. 10
0
        /// <summary>
        /// Обработчик под тип входных данных OPTION_SERIES
        /// </summary>
        /// <param name="price">цена БА</param>
        /// <param name="time">время до экспирации в долях года</param>
        /// <param name="optSer">опционная серия</param>
        /// <param name="rate">процентная ставка</param>
        /// <param name="barNum">индекс бара в серии</param>
        /// <returns>улыбка, восстановленная из цен опционов</returns>
        public InteractiveSeries Execute(double price, double time, IOptionSeries optSer, double scaleMult, double rate, int barNum)
        {
            int barsCount = ContextBarsCount;

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

            double f  = price;
            double dT = time;

            if (!DoubleUtil.IsPositive(f))
            {
                //throw new ScriptException("Argument 'price' contains NaN for some strange reason. f:" + f);
                return(Constants.EmptySeries);
            }
            if (!DoubleUtil.IsPositive(scaleMult))
            {
                //throw new ScriptException("Argument 'scaleMult' contains NaN for some strange reason. scaleMult:" + scaleMult);
                return(Constants.EmptySeries);
            }
            if (!DoubleUtil.IsPositive(dT))
            {
                return(Constants.EmptySeries);
            }
            if (Double.IsNaN(rate))
            {
                //throw new ScriptException("Argument 'rate' contains NaN for some strange reason. rate:" + rate);
                return(Constants.EmptySeries);
            }

            IOptionStrikePair[] strikes = (from strike in optSer.GetStrikePairs()
                                           //orderby strike.Strike ascending -- уже отсортировано
                                           select strike).ToArray();
            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

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

                double   putPxBtc, callPxBtc, putPxUsd, callPxUsd;
                double   putQty, callQty;
                DateTime putTime, callTime;
                {
                    putPxBtc = IvSmile.GetOptPrice(m_context, f, sInfo.Put, m_optionPxMode, sInfo.Tick * m_shiftAsk, sInfo.Tick * m_shiftBid, out putQty, out putTime);
                    putPxUsd = putPxBtc * scaleMult;
                    // Здесь нельзя сразу домножать на scaleMultiplier! Потому что тогда в метод FillNodeInfo пойдут бредовые цены.
                }

                {
                    callPxBtc = IvSmile.GetOptPrice(m_context, f, sInfo.Call, m_optionPxMode, sInfo.Tick * m_shiftAsk, sInfo.Tick * m_shiftBid, out callQty, out callTime);
                    callPxUsd = callPxBtc * scaleMult;
                    // Здесь нельзя сразу домножать на scaleMultiplier! Потому что тогда в метод FillNodeInfo пойдут бредовые цены.
                }

                double putSigma = Double.NaN, callSigma = Double.NaN, precision;
                if (DoubleUtil.IsPositive(putPxBtc))
                {
                    // Цену опциона переводим в баксы только в момент вычисления айви
                    putSigma = FinMath.GetOptionSigma(f, sInfo.Strike, dT, putPxUsd, rate, false, out precision);
                    putSigma = Math.Min(putSigma, m_maxSigma);
                    if (putSigma <= 0)
                    {
                        putSigma = Double.NaN;
                    }
                }
                if (DoubleUtil.IsPositive(callPxBtc))
                {
                    // Цену опциона переводим в баксы только в момент вычисления айви
                    callSigma = FinMath.GetOptionSigma(f, sInfo.Strike, dT, callPxUsd, rate, true, out precision);
                    callSigma = Math.Min(callSigma, m_maxSigma);
                    if (callSigma <= 0)
                    {
                        callSigma = Double.NaN;
                    }
                }

                InteractivePointActive ip = new InteractivePointActive();
                {
                    //ip.Color = (m_optionPxMode == OptionPxMode.Ask) ? Colors.DarkOrange : Colors.DarkCyan;
                    //ip.DragableMode = DragableMode.None;
                    //ip.Geometry = Geometries.Rect; // (optionPxMode == OptionPxMode.Ask) ? Geometries.Rect : Geometries.Rect;
                    //ip.IsActive = true;
                    //ip.Value = new Point(d2.V1, d2.V2);
                    //ip.Tooltip = String.Format("K:{0}; IV:{1:#0.00}", d2.V1, d2.V2 * PctMult);
                }

                InteractiveObject obj = new InteractiveObject(ip);

                if (m_optionType == StrikeType.Put)
                {
                    if (DoubleUtil.IsPositive(putSigma))
                    {
                        // Здесь используем первичную цену в том виде, как ее нам дал Дерибит
                        FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Put, m_optionPxMode, putPxBtc, putQty, putSigma, putTime, false, rate, scaleMult);
                        controlPoints.Add(obj);
                    }
                }
                else if (m_optionType == StrikeType.Call)
                {
                    if (DoubleUtil.IsPositive(callSigma))
                    {
                        // Здесь используем первичную цену в том виде, как ее нам дал Дерибит
                        FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Call, m_optionPxMode, callPxBtc, callQty, callSigma, callTime, false, rate, scaleMult);
                        controlPoints.Add(obj);
                    }
                }
                else if (m_optionType == StrikeType.Any)
                {
                    if (DoubleUtil.IsPositive(putSigma) && DoubleUtil.IsPositive(callSigma))
                    {
                        // Здесь используем первичную цену в том виде, как ее нам дал Дерибит
                        if (m_optionPxMode == OptionPxMode.Ask)
                        {
                            if (putSigma < callSigma)
                            {
                                FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Put, m_optionPxMode, putPxBtc, putQty, putSigma, putTime, false, rate, scaleMult);
                            }
                            else
                            {
                                FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Call, m_optionPxMode, callPxBtc, callQty, callSigma, callTime, false, rate, scaleMult);
                            }
                        }
                        else if (m_optionPxMode == OptionPxMode.Bid)
                        {
                            if (putSigma > callSigma)
                            {
                                FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Put, m_optionPxMode, putPxBtc, putQty, putSigma, putTime, false, rate, scaleMult);
                            }
                            else
                            {
                                FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Call, m_optionPxMode, callPxBtc, callQty, callSigma, callTime, false, rate, scaleMult);
                            }
                        }

                        controlPoints.Add(obj);
                    }
                    else if (DoubleUtil.IsPositive(putSigma) && Double.IsNaN(callSigma))
                    {
                        // Здесь используем первичную цену в том виде, как ее нам дал Дерибит
                        FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Put, m_optionPxMode, putPxBtc, putQty, putSigma, putTime, false, rate, scaleMult);
                        controlPoints.Add(obj);
                    }
                    else if (Double.IsNaN(putSigma) && DoubleUtil.IsPositive(callSigma))
                    {
                        // Здесь используем первичную цену в том виде, как ее нам дал Дерибит
                        FillNodeInfoDeribit(ip, f, dT, sInfo, StrikeType.Call, m_optionPxMode, callPxBtc, callQty, callSigma, callTime, false, rate, scaleMult);
                        controlPoints.Add(obj);
                    }
                }
            }

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

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

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

            if (!IvSmile.TryPrepareSmileInfo(m_context, f, dT, rate, optSer.ExpirationDate, scriptTime, baseSec.Symbol, res, out info))
            {
                return(Constants.EmptySeries);
            }

            return(res);
        }
Esempio n. 11
0
        public InteractiveSeries Execute(double price, double time, IOptionSeries optSer, double riskFreeRatePct, int barNum)
        {
            int barsCount = ContextBarsCount;

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

            // В оптимизации ничего рисовать не надо
            if (Context.IsOptimization)
            {
                return(Constants.EmptySeries);
            }

            double futPx = price;
            double dT    = time;

            if (!DoubleUtil.IsPositive(futPx))
            {
                // [{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 (!DoubleUtil.IsPositive(dT))
            {
                // [{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);
            }

            // TODO: Нужно ли писать отдельный код для лаборатории? Чтобы показывать позиции из симуляции?
            // if (!Context.Runtime.IsAgentMode)

            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            var allRealtimeSecs = Context.Runtime.Securities;

            IOptionStrikePair[] pairs = optSer.GetStrikePairs().ToArray();
            for (int j = 0; j < pairs.Length; j++)
            {
                IOptionStrikePair pair = pairs[j];

                #region Process put
                {
                    var put = pair.Put.Security;
                    // TODO: Нужно ли тут проверить наличие позиций???
                    //if (put.Positions.HavePositions)

                    ISecurityRt secRt;
                    if (put is ISecurityRt)
                    {
                        secRt = (ISecurityRt)put;
                    }
                    else
                    {
                        secRt = (from s in allRealtimeSecs
                                 where s.SecurityDescription.Equals(put) && (s is ISecurityRt)
                                 select(ISecurityRt) s).SingleOrDefault();
                    }

                    if ((secRt != null) && secRt.HasActiveOrders)
                    {
                        //secRt.SecurityDescription.TradePlace.DataSource
                        // ОТЛИЧНО! Эта коллекция позволит мне нарисовать свои заявки (это коллекция реальных заявок агента из таблицы My Orders)
                        var orders = secRt.Orders.ToList();
                        foreach (IOrder ord in orders)
                        {
                            if (!ord.IsActive)
                            {
                                continue;
                            }

                            // Объект ord является RealtimeOrder. Его идентификатор совпадает с OrderNumber в таблице MyOrders

                            if ((m_showLongOrders && ord.IsBuy) ||
                                ((!m_showLongOrders) && (!ord.IsBuy)))
                            {
                                // Почему-то InteractivePointLight хоть и давал себя настроить, но не отображался толком.
                                double sigma = FinMath.GetOptionSigma(futPx, pair.Strike, dT, ord.Price, riskFreeRatePct, false);
                                var    ip    = new InteractivePointActive(pair.Strike, sigma);
                                ip.Tooltip = String.Format(CultureInfo.InvariantCulture,
                                                           " F: {0}\r\n K: {1}; IV: {2:P2}\r\n {3} px {4} qty {5}",
                                                           futPx, pair.Strike, sigma, pair.Put.StrikeType, ord.Price, ord.RestQuantity);
                                controlPoints.Add(new InteractiveObject(ip));
                            }
                        }
                    }
                }
                #endregion Process put

                #region Process call
                {
                    var call = pair.Call.Security;
                    // TODO: Нужно ли тут проверить наличие позиций???
                    //if (call.Positions.HavePositions)

                    ISecurityRt secRt;
                    if (call is ISecurityRt)
                    {
                        secRt = (ISecurityRt)call;
                    }
                    else
                    {
                        secRt = (from s in allRealtimeSecs
                                 where s.SecurityDescription.Equals(call) && (s is ISecurityRt)
                                 select(ISecurityRt) s).SingleOrDefault();
                    }

                    if ((secRt != null) && secRt.HasActiveOrders)
                    {
                        // ОТЛИЧНО! Эта коллекция позволит мне нарисовать свои заявки (это коллекция реальных заявок агента из таблицы My Orders)
                        var orders = secRt.Orders.ToList();
                        foreach (IOrder ord in orders)
                        {
                            if (!ord.IsActive)
                            {
                                continue;
                            }

                            // Объект ord является RealtimeOrder. Его идентификатор совпадает с OrderNumber в таблице MyOrders

                            if ((m_showLongOrders && ord.IsBuy) ||
                                ((!m_showLongOrders) && (!ord.IsBuy)))
                            {
                                // Почему-то InteractivePointLight хоть и давал себя настроить, но не отображался толком.
                                double sigma = FinMath.GetOptionSigma(futPx, pair.Strike, dT, ord.Price, riskFreeRatePct, true);
                                var    ip    = new InteractivePointActive(pair.Strike, sigma);
                                ip.Tooltip = String.Format(CultureInfo.InvariantCulture,
                                                           " F: {0}\r\n K: {1}; IV: {2:P2}\r\n {3} px {4} qty {5}",
                                                           futPx, pair.Strike, sigma, pair.Call.StrikeType, ord.Price, ord.RestQuantity);
                                controlPoints.Add(new InteractiveObject(ip));
                            }
                        }
                    }
                }
                #endregion Process call
            } // End for (int j = 0; j < pairs.Length; j++)

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

            return(res);
        }
Esempio n. 12
0
        public InteractiveSeries Execute(IOptionSeries optSer, int barNum)
        {
            int barsCount = ContextBarsCount;

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

            IOptionStrikePair[]      pairs         = optSer.GetStrikePairs().ToArray();
            PositionsManager         posMan        = PositionsManager.GetManager(m_context);
            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            if (m_countFutures)
            {
                var futPositions = posMan.GetClosedOrActiveForBar(optSer.UnderlyingAsset);
                if (futPositions.Count > 0)
                {
                    double futQty, futCommission;
                    SingleSeriesProfile.GetTotalCommission(futPositions, barNum, m_longPositions, out futCommission, out futQty);

                    if (!DoubleUtil.IsZero(futQty))
                    {
                        InteractivePointActive ip = new InteractivePointActive(0, futQty);
                        ip.IsActive = true;
                        //ip.DragableMode = DragableMode.None;
                        //ip.Geometry = Geometries.Rect;
                        //ip.Color = Colors.DarkOrange;
                        ip.Tooltip = String.Format("Fut commission:{0}", futCommission);

                        controlPoints.Add(new InteractiveObject(ip));
                    }
                }
            }

            for (int j = 0; j < pairs.Length; j++)
            {
                IOptionStrikePair pair = pairs[j];
                double            putQty = 0, putCommission = Double.NaN;
                {
                    var putPositions = posMan.GetClosedOrActiveForBar(pair.Put.Security);
                    if (putPositions.Count > 0)
                    {
                        SingleSeriesProfile.GetTotalCommission(putPositions, barNum, m_longPositions, out putCommission, out putQty);
                    }
                }

                double callQty = 0, callCommission = Double.NaN;
                {
                    var callPositions = posMan.GetClosedOrActiveForBar(pair.Call.Security);
                    if (callPositions.Count > 0)
                    {
                        SingleSeriesProfile.GetTotalCommission(callPositions, barNum, m_longPositions, out callCommission, out callQty);
                    }
                }

                if ((!DoubleUtil.IsZero(putQty)) || (!DoubleUtil.IsZero(callQty)))
                {
                    double y = 0;
                    switch (m_optionType)
                    {
                    case StrikeType.Put:
                        y = putCommission;
                        break;

                    case StrikeType.Call:
                        y = callCommission;
                        break;

                    case StrikeType.Any:
                        y = putCommission + callCommission;
                        break;

                    default:
                        throw new NotImplementedException("OptionType: " + m_optionType);
                    }

                    // Не хочу видеть ячейки таблицы с NaN
                    if (Double.IsNaN(y))
                    {
                        continue;
                    }

                    if (
                        (!DoubleUtil.IsZero(y)) ||
                        ((m_optionType == StrikeType.Any) && ((!DoubleUtil.IsZero(putQty)) || (!DoubleUtil.IsZero(callQty))))) // Хотя вообще-то мы внутри if и второй блок проверок всегда true...
                    {
                        InteractivePointActive ip = new InteractivePointActive(pair.Strike, y);
                        ip.IsActive = true;
                        //ip.DragableMode = DragableMode.None;
                        //ip.Geometry = Geometries.Rect;
                        //ip.Color = Colors.DarkOrange;
                        ip.Tooltip = String.Format("K:{0}; Commission:{1}", pair.Strike, y);

                        controlPoints.Add(new InteractiveObject(ip));
                    }
                }
            }

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

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

            return(res);
        }
Esempio n. 13
0
        public InteractiveSeries Execute(double price, double time, int barNum)
        {
            int barsCount = ContextBarsCount;

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

            double futPx = price;
            double dT    = time;

            if (Double.IsNaN(dT) || (dT < Double.Epsilon) ||
                Double.IsNaN(futPx) || (futPx < Double.Epsilon))
            {
                return(Constants.EmptySeries);
            }

            double width = (SigmaMult * m_sigma * Math.Sqrt(dT)) * futPx;

            List <InteractiveObject> controlPoints = new List <InteractiveObject>();
            int    half = NumControlPoints / 2; // Целочисленное деление!
            double dK   = width / half;

            // Сдвигаю точки, чтобы избежать отрицательных значений
            while ((futPx - half * dK) <= Double.Epsilon)
            {
                half--;
            }
            for (int j = 0; j < NumControlPoints; j++)
            {
                double k = futPx + (j - half) * dK;

                InteractivePointLight ip;
                bool edgePoint = (j == 0) || (j == NumControlPoints - 1);
                if (m_showNodes ||
                    (edgePoint && m_showEdgeLabels)) // На крайние точки повешу Лейблы
                {
                    InteractivePointActive tmp = new InteractivePointActive();

                    tmp.IsActive = m_showNodes || (edgePoint && m_showEdgeLabels);
                    //tmp.DragableMode = DragableMode.None;
                    //tmp.Geometry = Geometries.Rect;
                    //tmp.Color = Colors.DarkOrange;
                    tmp.Tooltip = String.Format(CultureInfo.InvariantCulture,
                                                m_tooltipFormat, k, m_value * Constants.PctMult); // "K:{0}; V:{1:0.00}%"

                    if (edgePoint)
                    {
                        tmp.Label = String.Format(CultureInfo.InvariantCulture,
                                                  m_labelFormat, m_value * Constants.PctMult); // "V:{0:0.00}%"
                    }

                    ip = tmp;
                }
                else
                {
                    ip = new InteractivePointLight();
                }

                ip.Value = new Point(k, m_value);

                controlPoints.Add(new InteractiveObject(ip));
            }

            InteractiveSeries res = new InteractiveSeries(); // Здесь так надо -- мы делаем новую улыбку

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

            SmileInfo info = new SmileInfo();

            info.F            = futPx;
            info.dT           = dT;
            info.RiskFreeRate = 0;

            try
            {
                ConstantFunction spline = new ConstantFunction(m_value, futPx, dT);

                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);
        }
Esempio n. 14
0
        public InteractiveSeries Execute(double price, InteractiveSeries line, ISecurity sec, int barNum)
        {
            int barsCount = m_context.BarsCount;

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

            InteractiveSeries res = new InteractiveSeries(); // Здесь так надо -- мы делаем новую улыбку

            res.ClickEvent += InteractiveSplineOnClickEvent;

            m_clickableSeries = res;

            double    f        = price;
            double?   sigmaAtm = null;
            SmileInfo sInfo    = line.GetTag <SmileInfo>();

            if ((sInfo != null) && (sInfo.ContinuousFunction != null))
            {
                double tmp;
                if (sInfo.ContinuousFunction.TryGetValue(f, out tmp))
                {
                    if (!Double.IsNaN(tmp))
                    {
                        sigmaAtm = tmp;
                    }
                }
            }

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

            double h = Math.Max(m_minHeight, sigmaAtm.Value * m_offset);

            // Теперь определяем максимальный размах по вертикали
            if (line.ControlPoints.Count > 1)
            {
                var    cps = line.ControlPoints;
                double min = Double.MaxValue, max = Double.MinValue;
                for (int j = 0; j < cps.Count; j++)
                {
                    var    anchor = cps[j].Anchor;
                    double y      = anchor.ValueY;
                    if (y <= min)
                    {
                        min = y;
                    }
                    if (max <= y)
                    {
                        max = y;
                    }
                }

                if ((min < max) && (!Double.IsInfinity(max - min)))
                {
                    h = Math.Max(h, (max - min) * m_offset);
                }
            }

            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            {
                InteractivePointActive ip = new InteractivePointActive();
                ip.IsActive     = true;
                ip.DragableMode = DragableMode.None;
                ip.Geometry     = Geometries.Ellipse; // Geometries.TriangleDown;
                ip.Color        = AlphaColors.Magenta;
                double y = (sigmaAtm.Value - h);
                ip.Value = new Point(f, y);
                string yStr = y.ToString(m_tooltipFormat, CultureInfo.InvariantCulture);
                // По умолчанию формат 'P2' -- то есть отображение с точностью 2знака,
                // со знаком процента и с автоматическим умножением на 100.
                ip.Tooltip = String.Format(CultureInfo.InvariantCulture, "F:{0}; Y:{1}", f, yStr);

                SmileNodeInfo node = new SmileNodeInfo();
                node.OptPx    = f;
                node.Security = sec;
                node.PxMode   = OptionPxMode.Bid;

                node.Symbol   = node.Security.Symbol;
                node.DSName   = node.Security.SecurityDescription.DSName;
                node.Expired  = node.Security.SecurityDescription.Expired;
                node.FullName = node.Security.SecurityDescription.FullName;

                ip.Tag = node;

                controlPoints.Add(new InteractiveObject(ip));
            }

            {
                InteractivePointActive ip = new InteractivePointActive();
                ip.IsActive     = true;
                ip.DragableMode = DragableMode.None;
                ip.Geometry     = Geometries.Triangle;
                ip.Color        = AlphaColors.GreenYellow;
                double y = (sigmaAtm.Value + h);
                ip.Value = new Point(f, y);
                string yStr = y.ToString(m_tooltipFormat, CultureInfo.InvariantCulture);
                // По умолчанию формат 'P2' -- то есть отображение с точностью 2знака,
                // со знаком процента и с автоматическим умножением на 100.
                ip.Tooltip = String.Format(CultureInfo.InvariantCulture, "F:{0}; Y:{1}", f, yStr);

                SmileNodeInfo node = new SmileNodeInfo();
                node.OptPx    = f;
                node.Security = sec;
                node.PxMode   = OptionPxMode.Ask;

                node.Symbol   = node.Security.Symbol;
                node.DSName   = node.Security.SecurityDescription.DSName;
                node.Expired  = node.Security.SecurityDescription.Expired;
                node.FullName = node.Security.SecurityDescription.FullName;

                ip.Tag = node;

                controlPoints.Add(new InteractiveObject(ip));
            }

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

            return(res);
        }
Esempio n. 15
0
        private void InteractiveSplineOnQuoteIvEvent(object sender, InteractiveActionEventArgs eventArgs)
        {
            OptionPxMode pxMode = (m_qty > 0) ? OptionPxMode.Ask : OptionPxMode.Bid;

            PositionsManager posMan = PositionsManager.GetManager(m_context);

            if (posMan.BlockTrading)
            {
                //string msg = String.Format("[{0}] Trading is blocked. Please, change 'Block Trading' parameter.", m_optionPxMode);
                string msg = RM.GetStringFormat("OptHandlerMsg.PositionsManager.TradingBlocked", pxMode);
                m_context.Log(msg, MessageType.Info, true);
                return;
            }

            InteractivePointActive tmp = eventArgs.Point;

            if ((tmp == null) || (tmp.IsActive == null) || (!tmp.IsActive.Value) ||
                DoubleUtil.IsZero(m_qty))
            {
                //string msg = String.Format("[{0}] Unable to get direction of the order. Qty:{1}", pxMode, m_qty);
                string msg = RM.GetStringFormat("OptHandlerMsg.PositionsManager.UndefinedOrderDirection", pxMode, m_qty);
                m_context.Log(msg, MessageType.Error, true);
                return;
            }

            SmileNodeInfo nodeInfo = tmp.Tag as SmileNodeInfo;

            if (nodeInfo == null)
            {
                //string msg = String.Format("[{0}] There is no nodeInfo. Quote type: {1}; Strike: {2}", pxMode);
                string msg = RM.GetStringFormat(CultureInfo.InvariantCulture, "OptHandlerMsg.ThereIsNoNodeInfo",
                                                m_context.Runtime.TradeName, pxMode, eventArgs.Point.ValueX);
                m_context.Log(msg, MessageType.Error, true);
                return;
            }

            {
                string msg = String.Format(CultureInfo.InvariantCulture, "[{0}.ClickEvent] Strike: {1}", GetType().Name, tmp.ValueX);
                m_context.Log(msg, MessageType.Info, false);
            }

            nodeInfo.OptPx      = m_shiftIv;
            nodeInfo.ShiftOptPx = m_shiftPriceStep;
            nodeInfo.ClickTime  = DateTime.Now;
            nodeInfo.PxMode     = pxMode;

            // [2015-10-02] Подписка на данный инструмент, чтобы он появился в коллекции Context.Runtime.Securities
            var candids = (from s in Context.Runtime.Securities
                           where s.SecurityDescription.Name.Equals(nodeInfo.Symbol, StringComparison.InvariantCultureIgnoreCase)
                           select s).ToList();

            candids = (from s in candids
                       where s.SecurityDescription.DSName.Equals(nodeInfo.DSName, StringComparison.InvariantCultureIgnoreCase)
                       select s).ToList();
            ISecurity testSec = (from s in candids
                                 let secDesc = s.SecurityDescription
                                               where secDesc.FullName.Equals(nodeInfo.FullName, StringComparison.InvariantCultureIgnoreCase)
                                               select s).SingleOrDefault();

            if ((testSec == null) && (nodeInfo.Security != null))
            {
                ISecurity sec = nodeInfo.Security;
                int       bc  = sec.Bars.Count;
                string    msg = String.Format("[{0}] There is security DsName: {1}; Symbol: {2}; Security: {3} with {4} bars available.",
                                              pxMode, nodeInfo.DSName, nodeInfo.Symbol, nodeInfo.FullName, bc);
                Context.Log(msg, MessageType.Info, false);

                // Пересчитываю целочисленный параметр Qty в фактические лоты конкретного инструмента
                double actQty = Math.Abs(m_qty * sec.LotTick); // Модуль, потому что тут направление передается через PxMode
                nodeInfo.Qty = actQty;
            }
            else if ((nodeInfo.Pair != null) && (nodeInfo.Pair.Put != null))
            {
                // Аварийная ветка
                // Пересчитываю целочисленный параметр Qty в фактические лоты конкретного инструмента
                double actQty = Math.Abs(m_qty * nodeInfo.Pair.Put.LotTick); // Модуль, потому что тут направление передается через PxMode
                nodeInfo.Qty = actQty;
            }
            else
            {
                // Аварийная ветка
                // Не могу пересчитать целочисленный параметр Qty в фактические лоты конкретного инструмента!
                //double actQty = Math.Abs(m_qty * nodeInfo.Pair.Put.LotTick);
                nodeInfo.Qty = Math.Abs(m_qty); // Модуль, потому что тут направление передается через PxMode

                string msg = String.Format(CultureInfo.InvariantCulture, "[{0}.ClickEvent] LotTick will be set to 1.", GetType().Name);
                m_context.Log(msg, MessageType.Warning, false);
            }

            // Не страшно, если сюда пойдет null - posMan потом сам найдет нужный опцион
            nodeInfo.Security = testSec;

            // Передаю событие в PositionsManager
            //posMan.InteractiveSplineOnClickEvent(m_context, sender, eventArgs);
            posMan.InteractiveSplineOnQuoteIvEvent(m_context, sender, eventArgs);
        }
Esempio n. 16
0
        private int FillEditableCurve(SmileInfo info, List <InteractiveObject> controlPoints, List <double> xs, DragableMode dragMode)
        {
            if (xs.Count < 2)
            {
                string msg = String.Format("[DEBUG:{0}] Not enough points in argument xs. xs.Count:{0}", xs.Count);
                m_context.Log(msg, MessageType.Warning, true);
                return(0);
            }

            int    j          = 0;
            double k          = xs[0];
            double strikeStep = (xs[xs.Count - 1] - xs[0]) / (xs.Count - 1);

            while (k <= xs[xs.Count - 1])
            {
                if ((j < xs.Count) &&
                    (k <= xs[j]) && (xs[j] < k + strikeStep))
                {
                    #region Узел должен быть показан и доступен для редактирования
                    {
                        double sigma = info.ContinuousFunction.Value(xs[j]);

                        InteractivePointActive ip = new InteractivePointActive(xs[j], sigma);
                        ip.IsActive     = true;
                        ip.Geometry     = Geometries.Ellipse;
                        ip.DragableMode = dragMode;
                        ip.Color        = AlphaColors.GreenYellow;
                        ip.Tooltip      = String.Format("K:{0}; IV:{1:0.00}", xs[j], Constants.PctMult * sigma);

                        InteractiveObject obj = new InteractiveObject(ip);

                        controlPoints.Add(obj);
                    }
                    #endregion Узел должен быть показан и доступен для редактирования

                    j++;
                }
                else
                {
                    #region Просто точка без маркера
                    {
                        double sigma = info.ContinuousFunction.Value(k);

                        //InteractivePointActive ip = new InteractivePointActive(k, sigma);
                        //ip.IsActive = false;
                        //ip.Geometry = Geometries.Ellipse;
                        //ip.DragableMode = DragableMode.None;
                        //ip.Color = System.Windows.Media.Colors.Green;
                        //ip.Tooltip = String.Format("K:{0}; IV:{1:0.00}", k, Constants.PctMult * sigma);

                        InteractivePointLight ip  = new InteractivePointLight(k, sigma);
                        InteractiveObject     obj = new InteractiveObject(ip);

                        controlPoints.Add(obj);
                    }
                    #endregion Просто точка без маркера
                }

                k += strikeStep;
            }

            return(j);
        }
Esempio n. 17
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);

            IOptionStrikePair[]      pairs         = optSer.GetStrikePairs().ToArray();
            PositionsManager         posMan        = PositionsManager.GetManager(m_context);
            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            if (m_countFutures)
            {
                var futPositions = posMan.GetClosedOrActiveForBar(optSer.UnderlyingAsset);
                if (futPositions.Count > 0)
                {
                    double futQty, futAvgPx;
                    SingleSeriesProfile.GetAveragePrice(futPositions, barNum, m_longPositions, out futAvgPx, out futQty);

                    if (!DoubleUtil.IsZero(futQty))
                    {
                        double valueToDisplay = m_countQty ? futQty : futAvgPx;

                        // ReSharper disable once UseObjectOrCollectionInitializer
                        InteractivePointActive ip = new InteractivePointActive(0, valueToDisplay);
                        ip.IsActive = true;
                        //ip.DragableMode = DragableMode.None;
                        //ip.Geometry = Geometries.Rect;
                        //ip.Color = Colors.DarkOrange;
                        ip.Tooltip = String.Format("AvgPx:{0}; Qty:{1}", futAvgPx, futQty);

                        controlPoints.Add(new InteractiveObject(ip));
                    }
                }
            }

            for (int j = 0; j < pairs.Length; j++)
            {
                IOptionStrikePair pair = pairs[j];
                double            putQty = 0, putAvgPx = Double.NaN;
                {
                    var putPositions = posMan.GetClosedOrActiveForBar(pair.Put.Security);
                    if (putPositions.Count > 0)
                    {
                        SingleSeriesProfile.GetAveragePrice(putPositions, barNum, m_longPositions, out putAvgPx, out putQty);
                    }
                }

                double callQty = 0, callAvgPx = Double.NaN;
                {
                    var callPositions = posMan.GetClosedOrActiveForBar(pair.Call.Security);
                    if (callPositions.Count > 0)
                    {
                        SingleSeriesProfile.GetAveragePrice(callPositions, barNum, m_longPositions, out callAvgPx, out callQty);
                    }
                }

                if ((!DoubleUtil.IsZero(putQty)) || (!DoubleUtil.IsZero(callQty)))
                {
                    double averagePrice = 0, lotSize = 0;
                    switch (m_optionType)
                    {
                    case StrikeType.Put:
                        averagePrice = putAvgPx;
                        lotSize      = putQty;
                        break;

                    case StrikeType.Call:
                        averagePrice = callAvgPx;
                        lotSize      = callQty;
                        break;

                    //case StrikeType.Any:
                    //    y = putQty + callQty;
                    //    break;

                    default:
                        throw new NotSupportedException("OptionType: " + m_optionType);
                    }

                    // Не хочу видеть ячейки таблицы с NaN
                    if (Double.IsNaN(averagePrice))
                    {
                        continue;
                    }

                    if (!DoubleUtil.IsZero(lotSize))
                    {
                        double valueToDisplay = m_countQty ? lotSize : averagePrice;

                        // ReSharper disable once UseObjectOrCollectionInitializer
                        InteractivePointActive ip = new InteractivePointActive(pair.Strike, valueToDisplay);
                        ip.IsActive = true;
                        //ip.DragableMode = DragableMode.None;
                        //ip.Geometry = Geometries.Rect;
                        //ip.Color = Colors.DarkOrange;
                        ip.Tooltip = String.Format("K:{0}; AvgPx:{1}; Qty:{2}", pair.Strike, averagePrice, lotSize);

                        controlPoints.Add(new InteractiveObject(ip));
                    }
                }
            }

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

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

            SetHandlerInitialized(now);

            return(res);
        }
Esempio n. 18
0
        public InteractiveSeries Execute(double price, ISecurity sec, int barNum)
        {
            InteractiveSeries res = new InteractiveSeries();
            int barsCount         = m_context.BarsCount;

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

            res.ClickEvent -= InteractiveSplineOnClickEvent;
            res.ClickEvent += InteractiveSplineOnClickEvent;

            m_clickableSeries = res;

            double f = price;

            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            {
                InteractivePointActive ip = new InteractivePointActive(f, m_sigmaLow);
                ip.IsActive     = true;
                ip.DragableMode = DragableMode.None;
                ip.Geometry     = Geometries.Ellipse;
                ip.Color        = AlphaColors.BlueViolet;
                ip.Tooltip      = String.Format("F:{0}; Y:{1:0.00}%", f, m_sigmaLow * Constants.PctMult);

                SmileNodeInfo node = new SmileNodeInfo();
                node.OptPx    = f;
                node.Security = sec;
                node.PxMode   = OptionPxMode.Bid;

                node.Symbol   = node.Security.Symbol;
                node.DSName   = node.Security.SecurityDescription.DSName;
                node.Expired  = node.Security.SecurityDescription.Expired;
                node.FullName = node.Security.SecurityDescription.FullName;

                ip.Tag = node;

                controlPoints.Add(new InteractiveObject(ip));
            }

            {
                InteractivePointActive ip = new InteractivePointActive(f, m_sigmaHigh);
                ip.IsActive     = true;
                ip.DragableMode = DragableMode.None;
                ip.Geometry     = Geometries.Triangle;
                ip.Color        = AlphaColors.Green;
                ip.Tooltip      = String.Format("F:{0}; Y:{1:0.00}%", f, m_sigmaHigh * Constants.PctMult);

                SmileNodeInfo node = new SmileNodeInfo();
                node.OptPx    = f;
                node.Security = sec;
                node.PxMode   = OptionPxMode.Ask;

                node.Symbol   = node.Security.Symbol;
                node.DSName   = node.Security.SecurityDescription.DSName;
                node.Expired  = node.Security.SecurityDescription.Expired;
                node.FullName = node.Security.SecurityDescription.FullName;

                ip.Tag = node;

                controlPoints.Add(new InteractiveObject(ip));
            }

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

            return(res);
        }
Esempio n. 19
0
        /// <summary>
        /// Метод под флаг TemplateTypes.INTERACTIVESPLINE
        /// </summary>
        public InteractiveSeries Execute(InteractiveSeries quotes, InteractiveSeries smile, int barNum)
        {
            if ((quotes == null) || (smile == null))
            {
                return(Constants.EmptySeries);
            }

            int barsCount = m_context.BarsCount;

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

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

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

            InteractiveSeries res   = quotes;
            double            futPx = oldInfo.F;
            double            dT    = oldInfo.dT;

            foreach (InteractiveObject obj in res.ControlPoints)
            {
                SmileNodeInfo nodeInfo = obj.Anchor.Tag as SmileNodeInfo;
                if (nodeInfo == null)
                {
                    continue;
                }

                double realOptPx = nodeInfo.OptPx;
                bool   isCall    = (nodeInfo.OptionType == StrikeType.Call);

                double sigma = oldInfo.ContinuousFunction.Value(nodeInfo.Strike);
                if (Double.IsNaN(sigma) || (sigma < Double.Epsilon))
                {
                    //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;
                }

                double theorOptPx = FinMath.GetOptionPrice(futPx, nodeInfo.Strike, dT, sigma, oldInfo.RiskFreeRate, isCall);
                if (Double.IsNaN(theorOptPx) || (theorOptPx < Double.Epsilon))
                {
                    //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 (nodeInfo.PxMode == OptionPxMode.Ask)
                {
                    double doLevel = theorOptPx - m_widthPx * nodeInfo.Pair.Tick;
                    if (realOptPx <= doLevel)
                    {
                        var anchor = (InteractivePointActive)obj.Anchor;

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

                        tmp.IsActive = true;
                        tmp.Tag      = anchor.Tag;
                        tmp.Tooltip  = null; // anchor.Tooltip;
                        int    decimals = (nodeInfo.Security != null) ? nodeInfo.Security.Decimals : 0;
                        string pot      = Math.Abs(theorOptPx - realOptPx).ToString("N" + decimals, CultureInfo.InvariantCulture);
                        tmp.Label        = anchor.Tooltip + " (" + pot + ")";
                        tmp.ValueX       = anchor.ValueX;
                        tmp.ValueY       = anchor.ValueY + m_outlet;
                        tmp.DragableMode = DragableMode.None;
                        tmp.Size         = m_outletSize;

                        //tmp.Color = Colors.White;
                        //tmp.Geometry = m_outletGeometry; // Geometries.Ellipse;

                        obj.ControlPoint1 = tmp;
                    }
                }

                if (nodeInfo.PxMode == OptionPxMode.Bid)
                {
                    double upLevel = theorOptPx + m_widthPx * nodeInfo.Pair.Tick;
                    if (realOptPx >= upLevel)
                    {
                        var anchor = (InteractivePointActive)obj.Anchor;

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

                        tmp.IsActive = true;
                        tmp.Tag      = anchor.Tag;
                        tmp.Tooltip  = null; // anchor.Tooltip;
                        int    decimals = (nodeInfo.Security != null) ? nodeInfo.Security.Decimals : 0;
                        string pot      = Math.Abs(theorOptPx - realOptPx).ToString("N" + decimals, CultureInfo.InvariantCulture);
                        tmp.Label        = anchor.Tooltip + " (" + pot + ")";
                        tmp.ValueX       = anchor.ValueX;
                        tmp.ValueY       = anchor.ValueY - m_outlet;
                        tmp.DragableMode = DragableMode.None;
                        tmp.Size         = m_outletSize;

                        //tmp.Color = Colors.White;
                        //tmp.Geometry = m_outletGeometry; // Geometries.Ellipse;

                        obj.ControlPoint1 = tmp;
                    }
                }
            }

            res.ClickEvent -= InteractiveSplineOnClickEvent;
            res.ClickEvent += InteractiveSplineOnClickEvent;

            m_clickableSeries = res;

            return(res);
        }
Esempio n. 20
0
        public InteractiveSeries Execute(double time, InteractiveSeries smile, IOptionSeries optSer, int barNum)
        {
            //InteractiveSeries res = context.LoadObject(cashKey + "positionDelta") as InteractiveSeries;
            //if (res == null)
            //{
            //    res = new InteractiveSeries();
            //    context.StoreObject(cashKey + "positionDelta", res);
            //}

            InteractiveSeries res = new InteractiveSeries();
            int barsCount         = ContextBarsCount;

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

            //double F = prices[prices.Count - 1];
            double dT = time;

            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 (smile == null)
            {
                string msg = String.Format("[{0}] Argument 'smile' must be filled with InteractiveSeries.", GetType().Name);
                m_context.Log(msg, MessageType.Error, true);
                return(res);
            }

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

            if (oldInfo == null)
            {
                string msg = String.Format("[{0}] Property Tag of object smile must be filled with SmileInfo. Tag:{1}", GetType().Name, smile.Tag);
                m_context.Log(msg, MessageType.Error, true);
                return(res);
            }

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

            List <double> xs          = new List <double>();
            List <double> ys          = new List <double>();
            var           smilePoints = smile.ControlPoints;

            IOptionStrikePair[]      pairs         = optSer.GetStrikePairs().ToArray();
            PositionsManager         posMan        = PositionsManager.GetManager(m_context);
            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            foreach (InteractiveObject iob in smilePoints)
            {
                double rawVega, f = iob.Anchor.ValueX;
                if (TryEstimateVega(posMan, optSer, pairs, smile, m_greekAlgo, f, m_sigmaStep, dT, out rawVega))
                {
                    // Переводим вегу в дифференциал 'изменение цены за 1% волы'.
                    rawVega /= Constants.PctMult;

                    InteractivePointActive ip = new InteractivePointActive();
                    ip.IsActive = m_showNodes;
                    //ip.DragableMode = DragableMode.None;
                    //ip.Geometry = Geometries.Rect;
                    //ip.Color = System.Windows.Media.Colors.Green;
                    double y = rawVega;
                    ip.Value = new Point(f, y);
                    string yStr = y.ToString(m_tooltipFormat, CultureInfo.InvariantCulture);
                    ip.Tooltip = String.Format("F:{0}; V:{1}", f, yStr);

                    controlPoints.Add(new InteractiveObject(ip));

                    xs.Add(f);
                    ys.Add(y);
                }
            }

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

            try
            {
                if (xs.Count >= BaseCubicSpline.MinNumberOfNodes)
                {
                    SmileInfo info = new SmileInfo();
                    info.F            = oldInfo.F;
                    info.dT           = oldInfo.dT;
                    info.RiskFreeRate = oldInfo.RiskFreeRate;

                    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);
        }
Esempio n. 21
0
        public InteractiveSeries Execute(double price, double time, InteractiveSeries smile, IOptionSeries optSer, double ratePct, int barNum)
        {
            int barsCount = ContextBarsCount;

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

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

            if ((oldInfo == null) ||
                (oldInfo.ContinuousFunction == null) || (oldInfo.ContinuousFunctionD1 == 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);

            double futPx = price;
            double dT    = time;

            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);
                if (wasInitialized)
                {
                    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);
                if (wasInitialized)
                {
                    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 ivAtm, slopeAtm;

            if ((!oldInfo.ContinuousFunction.TryGetValue(futPx, out ivAtm)) ||
                (!oldInfo.ContinuousFunctionD1.TryGetValue(futPx, out slopeAtm)))
            {
                return(Constants.EmptySeries);
            }

            if (m_setIvByHands)
            {
                ivAtm = m_ivAtmPct.Value / Constants.PctMult;
            }

            if (m_setSlopeByHands)
            {
                slopeAtm = m_internalSlopePct.Value / Constants.PctMult;
                slopeAtm = slopeAtm / futPx / Math.Sqrt(dT);
            }

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

            if (Double.IsNaN(slopeAtm))
            {
                // [{0}] Smile skew at the money must be some number. skewAtm:{1}
                string msg = RM.GetStringFormat("OptHandlerMsg.SkewAtmMustBeNumber", GetType().Name, slopeAtm);
                if (wasInitialized)
                {
                    m_context.Log(msg, MessageType.Error, true);
                }
                return(Constants.EmptySeries);
            }

            //{
            //    string msg = String.Format("[DEBUG:{0}] ivAtm:{1}; shift:{2}; depth:{3};   F:{4}; dT:{5}; ",
            //        GetType().Name, ivAtm, shift, depth, F, dT);
            //    context.Log(msg, MessageType.Info, true);
            //}

            SmileFunction3 tempFunc = new SmileFunction3(ivAtm, m_shift, 0.5, futPx, dT);
            double         depth    = tempFunc.GetDepthUsingSlopeATM(slopeAtm);

            SmileFunction3 smileFunc = new SmileFunction3(ivAtm, m_shift, depth, futPx, dT);

            if (!m_setIvByHands)
            {
                m_ivAtmPct.Value = ivAtm * Constants.PctMult;
            }
            m_depthPct.Value = depth * Constants.PctMult;

            if (!m_setSlopeByHands)
            {
                double dSigmaDx = slopeAtm * futPx * Math.Sqrt(dT);
                m_internalSlopePct.Value = dSigmaDx * Constants.PctMult;
            }

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

            IOptionStrikePair[] pairs = optSer.GetStrikePairs().ToArray();

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

            double minK  = pairs[0].Strike;
            double dK    = pairs[1].Strike - pairs[0].Strike;
            double width = (SigmaMult * ivAtm * Math.Sqrt(dT)) * futPx;

            width = Math.Max(width, 2 * dK);
            // Generate left invisible tail
            if (m_generateTails)
            {
                GaussSmile.AppendLeftTail(smileFunc, xs, ys, minK, dK, false);
            }

            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

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

                double k     = pair.Strike;
                double sigma = smileFunc.Value(k);
                double vol   = sigma;

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

                InteractivePointActive ip = new InteractivePointActive(k, vol);
                //ip.Color = (optionPxMode == OptionPxMode.Ask) ? Colors.DarkOrange : Colors.DarkCyan;
                //ip.DragableMode = DragableMode.None;
                //ip.Geometry = Geometries.Rect; // (optionPxMode == OptionPxMode.Ask) ? Geometries.Rect : Geometries.Rect;

                // Иначе неправильно выставляются координаты???
                //ip.Tooltip = String.Format("K:{0}; IV:{1:0.00}", k, PctMult * sigma);

                if (showPoint)
                {
                    if (k <= futPx) // Puts
                    {
                        FillNodeInfo(ip, futPx, dT, pair, StrikeType.Put, OptionPxMode.Mid, sigma, false, m_isVisiblePoints, ratePct);
                    }
                    else // Calls
                    {
                        FillNodeInfo(ip, futPx, dT, pair, StrikeType.Call, OptionPxMode.Mid, sigma, false, m_isVisiblePoints, ratePct);
                    }
                }

                InteractiveObject obj = new InteractiveObject(ip);

                if (showPoint)
                {
                    controlPoints.Add(obj);
                }

                xs.Add(k);
                ys.Add(vol);
            }

            // ReSharper disable once UseObjectOrCollectionInitializer
            InteractiveSeries res = new InteractiveSeries();

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

            double maxK = pairs[pairs.Length - 1].Strike;

            // Generate right invisible tail
            if (m_generateTails)
            {
                GaussSmile.AppendRightTail(smileFunc, xs, ys, maxK, dK, false);
            }

            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;

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

            res.Tag = info;

            SetHandlerInitialized(now);

            return(res);
        }
        public InteractiveSeries Execute(double price, double time, InteractiveSeries smile, IOptionSeries optSer, double scaleMult, double ratePct, int barNum)
        {
            int barsCount = ContextBarsCount;

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

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

            if ((oldInfo == null) ||
                (oldInfo.ContinuousFunction == null) || (oldInfo.ContinuousFunctionD1 == 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);

            double futPx = price;
            double dT    = time;

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

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

            if (!DoubleUtil.IsPositive(scaleMult))
            {
                //throw new ScriptException("Argument 'scaleMult' contains NaN for some strange reason. scaleMult:" + scaleMult);
                return(Constants.EmptySeries);
            }

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

            double ivAtm, slopeAtm, shape;

            if ((!oldInfo.ContinuousFunction.TryGetValue(futPx, out ivAtm)) ||
                (!oldInfo.ContinuousFunctionD1.TryGetValue(futPx, out slopeAtm)))
            {
                return(Constants.EmptySeries);
            }

            if (m_setIvByHands)
            {
                ivAtm = m_ivAtmPct.Value / Constants.PctMult;
            }

            if (m_setSlopeByHands)
            {
                slopeAtm = m_slopePct.Value / Constants.PctMult;
                //slopeAtm = slopeAtm / F / Math.Pow(dT, Pow + shape);
            }

            //if (setShapeByHands)
            {
                shape = m_shapePct.Value / Constants.PctMult;
            }

            if (!DoubleUtil.IsPositive(ivAtm))
            {
                // [{0}] ivAtm must be positive value. ivAtm:{1}
                string msg = RM.GetStringFormat("OptHandlerMsg.IvAtmMustBePositive", GetType().Name, ivAtm);
                if (wasInitialized)
                {
                    m_context.Log(msg, MessageType.Error, true);
                }
                return(Constants.EmptySeries);
            }

            if (Double.IsNaN(slopeAtm))
            {
                // [{0}] Smile skew at the money must be some number. skewAtm:{1}
                string msg = RM.GetStringFormat("OptHandlerMsg.SkewAtmMustBeNumber", GetType().Name, slopeAtm);
                if (wasInitialized)
                {
                    m_context.Log(msg, MessageType.Error, true);
                }
                return(Constants.EmptySeries);
            }

            SmileInfo templateInfo;

            #region Fill templateInfo
            if (m_useLocalTemplate)
            {
                InteractiveSeries templateSmile = m_context.LoadObject(m_frozenSmileId) as InteractiveSeries;
                if (templateSmile == null)
                {
                    // [{0}] There is no LOCAL smile with ID:{1}
                    string msg = RM.GetStringFormat("SmileImitation5.NoLocalSmile", GetType().Name, m_frozenSmileId);
                    if (wasInitialized)
                    {
                        m_context.Log(msg, MessageType.Error, true);
                    }
                    return(Constants.EmptySeries);
                }

                SmileInfo locInfo = new SmileInfo();
                locInfo.F            = futPx;
                locInfo.dT           = dT;
                locInfo.RiskFreeRate = oldInfo.RiskFreeRate;

                List <double> locXs = new List <double>();
                List <double> locYs = new List <double>();
                foreach (InteractiveObject oldObj in templateSmile.ControlPoints)
                {
                    if (!oldObj.AnchorIsActive)
                    {
                        continue;
                    }

                    double k     = oldObj.Anchor.ValueX;
                    double sigma = oldObj.Anchor.ValueY;

                    double x = Math.Log(k / futPx) / Math.Pow(dT, DefaultPow + shape) / ivAtm;
                    double sigmaNormalized = sigma / ivAtm;

                    locXs.Add(x);
                    locYs.Add(sigmaNormalized);
                }

                try
                {
                    NotAKnotCubicSpline spline = new NotAKnotCubicSpline(locXs, locYs);

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

                    templateInfo = locInfo;
                }
                catch (Exception ex)
                {
                    m_context.Log(ex.ToString(), MessageType.Error, true);
                    return(Constants.EmptySeries);
                }
            }
            else
            {
                //templateSmile = context.LoadGlobalObject(globalSmileID, true) as InteractiveSeries;
                templateInfo = m_context.LoadGlobalObject(m_globalSmileId, true) as SmileInfo;
                if (templateInfo == null)
                {
                    // [{0}] There is no global templateInfo with ID:{1}. I'll try to use default one.
                    string msg = RM.GetStringFormat("SmileImitation5.TemplateWasSaved", GetType().Name, m_globalSmileId);
                    m_context.Log(msg, MessageType.Error, true);

                    System.Xml.Linq.XDocument xDoc  = System.Xml.Linq.XDocument.Parse(SmileFunction5.XmlSmileRiz4Nov1);
                    System.Xml.Linq.XElement  xInfo = xDoc.Root;
                    SmileInfo templateSmile         = SmileInfo.FromXElement(xInfo);

                    // Обновляю уровень IV ATM?
                    if (Double.IsNaN(ivAtm))
                    {
                        ivAtm = oldInfo.ContinuousFunction.Value(futPx);

                        m_context.Log(String.Format("[DEBUG:{0}] ivAtm was NaN. I'll use value ivAtm:{1}", GetType().Name, ivAtm), MessageType.Warning, true);

                        if (Double.IsNaN(ivAtm))
                        {
                            throw new Exception(String.Format("[DEBUG:{0}] ivAtm is NaN.", GetType().Name));
                        }
                    }

                    templateSmile.F            = futPx;
                    templateSmile.dT           = dT;
                    templateSmile.RiskFreeRate = oldInfo.RiskFreeRate;

                    m_context.StoreGlobalObject(m_globalSmileId, templateSmile, true);

                    // [{0}] Default templateInfo was saved to Global Cache with ID:{1}.
                    msg = RM.GetStringFormat("SmileImitation5.TemplateWasSaved", GetType().Name, m_globalSmileId);
                    m_context.Log(msg, MessageType.Warning, true);

                    templateInfo = templateSmile;
                }
            }
            #endregion Fill templateInfo

            if (!m_setIvByHands)
            {
                m_ivAtmPct.Value = ivAtm * Constants.PctMult;
            }

            if (!m_setShapeByHands)
            {
                // так я ещё не умею
            }

            if (!m_setSlopeByHands)
            {
                // Пересчитываю наклон в безразмерку
                double dSigmaDx = slopeAtm * futPx * Math.Pow(dT, DefaultPow + shape);
                m_slopePct.Value = dSigmaDx * Constants.PctMult;

                // и теперь апдейчу локальную переменную slopeAtm:
                slopeAtm = m_slopePct.Value / Constants.PctMult;
            }

            // Это функция в нормированных координатах
            // поэтому достаточно обычной симметризации
            // PROD-3111: заменяю вызов на SmileFunctionExtended
            //SimmetrizeFunc simmFunc = new SimmetrizeFunc(templateInfo.ContinuousFunction);
            //SimmetrizeFunc simmFuncD1 = new SimmetrizeFunc(templateInfo.ContinuousFunctionD1);
            //SmileFunction5 smileFunc = new SmileFunction5(simmFunc, simmFuncD1, ivAtm, slopeAtm, shape, futPx, dT);
            SmileFunctionExtended smileFunc = new SmileFunctionExtended(
                (NotAKnotCubicSpline)templateInfo.ContinuousFunction, ivAtm, slopeAtm, shape, futPx, dT);
            smileFunc.UseTails = m_useSmileTails;

            List <double>       xs    = new List <double>();
            List <double>       ys    = new List <double>();
            IOptionStrikePair[] pairs = optSer.GetStrikePairs().ToArray();

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

            double minK    = pairs[0].Strike;
            double maxK    = pairs[pairs.Length - 1].Strike;
            double futStep = optSer.UnderlyingAsset.Tick;
            double dK      = pairs[1].Strike - pairs[0].Strike;
            double width   = (SigmaMult * ivAtm * Math.Sqrt(dT)) * futPx;
            width = Math.Max(width, 10 * dK);
            // Нельзя вылезать за границу страйков???
            width = Math.Min(width, Math.Abs(futPx - minK));
            width = Math.Min(width, Math.Abs(maxK - futPx));
            // Generate left invisible tail
            if (m_generateTails)
            {
                GaussSmile.AppendLeftTail(smileFunc, xs, ys, minK, dK, false);
            }

            SortedDictionary <double, IOptionStrikePair> strikePrices;
            if (!SmileImitation5.TryPrepareImportantPoints(pairs, futPx, futStep, width, out strikePrices))
            {
                string msg = String.Format("[{0}] It looks like there is no suitable points for the smile. pairs.Length:{1}", GetType().Name, pairs.Length);
                if (wasInitialized)
                {
                    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);
                //IOptionStrikePair pair = pairs[j];
                //// Сверхдалекие страйки игнорируем
                //if ((pair.Strike < futPx - width) || (futPx + width < pair.Strike))
                //{
                //    showPoint = false;
                //}

                //double k = pair.Strike;
                double k = kvp.Key;
                double sigma;
                if (!smileFunc.TryGetValue(k, out sigma))
                {
                    continue;
                }
                double vol = sigma;

                if (!DoubleUtil.IsPositive(sigma))
                {
                    continue;
                }

                //InteractivePointActive ip = new InteractivePointActive(k, vol);
                //ip.Color = (optionPxMode == OptionPxMode.Ask) ? Colors.DarkOrange : Colors.DarkCyan;
                //ip.DragableMode = DragableMode.None;
                //ip.Geometry = Geometries.Rect; // (optionPxMode == OptionPxMode.Ask) ? Geometries.Rect : Geometries.Rect;

                // Иначе неправильно выставляются координаты???
                //ip.Tooltip = String.Format("K:{0}; IV:{1:0.00}", k, PctMult * sigma);

                InteractivePointLight ip;
                if (showPoint)
                {
                    var tip = new InteractivePointActive(k, vol);
                    if (k <= futPx) // Puts
                    {
                        SmileImitationDeribit5.FillNodeInfo(tip, futPx, dT, kvp.Value, StrikeType.Put, OptionPxMode.Mid, sigma, false, m_showNodes, scaleMult, ratePct);
                    }
                    else // Calls
                    {
                        SmileImitationDeribit5.FillNodeInfo(tip, futPx, dT, kvp.Value, StrikeType.Call, OptionPxMode.Mid, sigma, false, m_showNodes, scaleMult, ratePct);
                    }
                    ip = tip;
                }
                else
                {
                    ip = new InteractivePointLight(k, vol);
                }

                InteractiveObject obj = new InteractiveObject(ip);

                //if (showPoint)
                // Теперь мы понимаем, что точки либо рисуются
                // потому что это страйки (и тогда они автоматом InteractivePointActive)
                // либо они присутствуют, но не рисуются их узлы. Потому что они InteractivePointLight.
                {
                    controlPoints.Add(obj);
                }

                xs.Add(k);
                ys.Add(vol);
            }

            // ReSharper disable once UseObjectOrCollectionInitializer
            InteractiveSeries res = new InteractiveSeries();
            res.ControlPoints = new ReadOnlyCollection <InteractiveObject>(controlPoints);

            // Generate right invisible tail
            if (m_generateTails)
            {
                GaussSmile.AppendRightTail(smileFunc, xs, ys, maxK, dK, false);
            }

            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;

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

            res.Tag = info;

            SetHandlerInitialized(now);

            return(res);
        }
Esempio n. 23
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);
        }
Esempio n. 24
0
        public InteractiveSeries Execute(InteractiveSeries deltaProfile, int barNum)
        {
            //InteractiveSeries res = context.LoadObject(cashKey + "positionDelta") as InteractiveSeries;
            //if (res == null)
            //{
            //    res = new InteractiveSeries();
            //    context.StoreObject(cashKey + "positionDelta", res);
            //}

            InteractiveSeries res = new InteractiveSeries();
            int barsCount         = ContextBarsCount;

            if (barNum < barsCount - 1)
            {
                return(res);
            }

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

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

            if ((sInfo == null) ||
                (sInfo.ContinuousFunction == null) || (sInfo.ContinuousFunctionD1 == null))
            {
                return(res);
            }

            List <double>            xs            = new List <double>();
            List <double>            ys            = new List <double>();
            var                      deltaPoints   = deltaProfile.ControlPoints;
            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            foreach (InteractiveObject iob in deltaPoints)
            {
                double rawGamma, f = iob.Anchor.ValueX;
                if (sInfo.ContinuousFunctionD1.TryGetValue(f, out rawGamma))
                {
                    InteractivePointActive ip = new InteractivePointActive();
                    ip.IsActive = m_showNodes;
                    //ip.DragableMode = DragableMode.None;
                    //ip.Geometry = Geometries.Rect;
                    //ip.Color = System.Windows.Media.Colors.Orange;
                    double y = rawGamma;
                    ip.Value = new Point(f, y);
                    string yStr = y.ToString(m_tooltipFormat, CultureInfo.InvariantCulture);
                    ip.Tooltip = String.Format(CultureInfo.InvariantCulture, "F:{0}; G:{1}", f, yStr);

                    controlPoints.Add(new InteractiveObject(ip));

                    xs.Add(f);
                    ys.Add(y);
                }
            }

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

            try
            {
                if (xs.Count >= BaseCubicSpline.MinNumberOfNodes)
                {
                    SmileInfo info = new SmileInfo();
                    info.F            = sInfo.F;
                    info.dT           = sInfo.dT;
                    info.RiskFreeRate = sInfo.RiskFreeRate;

                    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);
        }
Esempio n. 25
0
        public InteractiveSeries Execute(double time, InteractiveSeries smile, IOptionSeries optSer, int barNum)
        {
            int barsCount = ContextBarsCount;

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

            //double F = prices[prices.Count - 1];
            double dT = time;

            if (!DoubleUtil.IsPositive(dT))
            {
                // [{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 (smile == null)
            {
                string msg = String.Format("[{0}] Argument 'smile' must be filled with InteractiveSeries.", GetType().Name);
                m_context.Log(msg, MessageType.Error, true);
                return(Constants.EmptySeries);
            }

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

            if (oldInfo == null)
            {
                string msg = String.Format("[{0}] Property Tag of object smile must be filled with SmileInfo. Tag:{1}", GetType().Name, smile.Tag);
                m_context.Log(msg, MessageType.Error, true);
                return(Constants.EmptySeries);
            }

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

            IOptionStrikePair[]      pairs         = optSer.GetStrikePairs().ToArray();
            PositionsManager         posMan        = PositionsManager.GetManager(m_context);
            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            while (f <= m_maxStrike)
            {
                double rawDelta;
                GetBaseDelta(posMan, optSer.UnderlyingAsset, optSer.UnderlyingAsset.Bars.Count - 1, f, out rawDelta);

                for (int j = 0; j < pairs.Length; j++)
                {
                    IOptionStrikePair pair = pairs[j];
                    double            totalDelta;
                    //double putDelta = FinMath.GetOptionDelta(f, pair.Strike, dT, sigma.Value, 0, false);
                    GetPairDelta(posMan, smile, pair, f, dT, out totalDelta);
                    rawDelta += totalDelta;
                }

                InteractivePointActive ip = new InteractivePointActive();
                ip.IsActive = m_showNodes;
                //ip.DragableMode = DragableMode.None;
                //ip.Geometry = Geometries.Rect;
                //ip.Color = AlphaColors.Green;
                double y = rawDelta;
                ip.Value = new Point(f, y);
                string yStr = y.ToString(m_tooltipFormat, CultureInfo.InvariantCulture);
                ip.Tooltip = String.Format(CultureInfo.InvariantCulture, "F:{0}; D:{1}", f, yStr);

                controlPoints.Add(new InteractiveObject(ip));

                xs.Add(f);
                ys.Add(y);

                f += m_strikeStep;
            }

            InteractiveSeries res = new InteractiveSeries(); // Здесь так надо -- мы делаем новую улыбку

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

            try
            {
                if (xs.Count >= BaseCubicSpline.MinNumberOfNodes)
                {
                    SmileInfo info = new SmileInfo();
                    info.F            = oldInfo.F;
                    info.dT           = oldInfo.dT;
                    info.RiskFreeRate = oldInfo.RiskFreeRate;

                    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);
        }
Esempio n. 26
0
        public InteractiveSeries Execute(double time, InteractiveSeries smile, IOptionSeries optSer, double btcUsdIndex, int barNum)
        {
            int barsCount = ContextBarsCount;

            if ((barNum < barsCount - 1) || (smile == null) || (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);

            double dT = time;

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

            if (!DoubleUtil.IsPositive(btcUsdIndex))
            {
                // TODO: сделать ресурс! [{0}] Price of BTC/USD must be positive value. scaleMult:{1}
                //string msg = RM.GetStringFormat("OptHandlerMsg.CurrencyScaleMustBePositive", GetType().Name, scaleMult);
                string msg = String.Format("[{0}] Price of BTC/USD must be positive value. scaleMult:{1}", GetType().Name, btcUsdIndex);
                if (wasInitialized)
                {
                    m_context.Log(msg, MessageType.Error, true);
                }
                return(Constants.EmptySeries);
            }

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

            if (oldInfo == null)
            {
                string msg = String.Format("[{0}] Property Tag of object smile must be filled with SmileInfo. Tag:{1}", GetType().Name, smile.Tag);
                if (wasInitialized)
                {
                    m_context.Log(msg, MessageType.Error, false);
                }
                return(Constants.EmptySeries);
            }

            double futPx = oldInfo.F;

            double ivAtm;

            if (!oldInfo.ContinuousFunction.TryGetValue(futPx, out ivAtm))
            {
                string msg = String.Format("[{0}] Unable to get IV ATM from smile. Tag:{1}", GetType().Name, smile.Tag);
                if (wasInitialized)
                {
                    m_context.Log(msg, MessageType.Error, true);
                }
                return(Constants.EmptySeries);
            }

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

            List <double>    xs      = new List <double>();
            List <double>    ys      = new List <double>();
            double           futStep = optSer.UnderlyingAsset.Tick;
            PositionsManager posMan  = PositionsManager.GetManager(m_context);
            ReadOnlyCollection <IPosition> basePositions = posMan.GetClosedOrActiveForBar(optSer.UnderlyingAsset);
            var optPositions = SingleSeriesProfile.GetAllOptionPositions(posMan, pairs);

            SortedDictionary <double, IOptionStrikePair> futPrices;

            if (!SmileImitation5.TryPrepareImportantPoints(pairs, futPx, futStep, -1, out futPrices))
            {
                string msg = String.Format("[{0}] It looks like there is no suitable points for the smile. pairs.Length:{1}", GetType().Name, pairs.Length);
                if (wasInitialized)
                {
                    m_context.Log(msg, MessageType.Warning, true);
                }
                return(Constants.EmptySeries);
            }

            // Чтобы учесть базис между фьючерсом и индексом, вычисляю их отношение:
            // Пример: BtcInd==9023; FutPx==8937 --> indexDivByFutRatio == 1.009623
            double indexDivByFutRatio = btcUsdIndex / futPx;

            List <InteractiveObject> controlPoints = new List <InteractiveObject>();
            // Список точек для вычисления дельт + улыбки для этих точек
            var deltaPoints = new List <Tuple <double, InteractivePointActive> >();

            foreach (var kvp in futPrices)
            {
                // Если у нас новая цена фьючерса, значит, будет новая цена индекса
                double f = kvp.Key;
                // И при пересчете опционов в баксы НУЖНО ИСПОЛЬЗОВАТЬ ИМЕННО ЕЁ!!!
                double newScaleMult = f * indexDivByFutRatio;

                bool tradableStrike = (kvp.Value != null);

                CashPnlUsd cashPnlUsd;
                CashPnlBtc cashPnlBtc;
                GetBasePnl(basePositions, lastBarIndex, f, m_futNominal, out cashPnlUsd, out cashPnlBtc);
                double cashDollars = cashPnlUsd.CashUsd;
                double pnlDollars  = cashPnlUsd.PnlUsd;
                double cashBtc     = cashPnlBtc.CashBtc;
                double pnlBtc      = cashPnlBtc.PnlBtc;

                SmileInfo actualSmile = SingleSeriesProfile.GetActualSmile(oldInfo, m_greekAlgo, f);

                // Флаг того, что ПНЛ по всем инструментам был расчитан верно
                bool pnlIsCorrect = true;
                for (int j = 0; (j < pairs.Length) && pnlIsCorrect; j++)
                {
                    var tuple = optPositions[j];
                    IOptionStrikePair pair = pairs[j];
                    //int putBarCount = pair.Put.UnderlyingAsset.Bars.Count;
                    //int callBarCount = pair.Call.UnderlyingAsset.Bars.Count;

                    CashPnlUsd pairCashUsd;
                    CashPnlBtc pairCashBtc;
                    bool       localRes = TryGetPairPnl(actualSmile, pair.Strike, lastBarIndex, lastBarIndex,
                                                        tuple.Item1, tuple.Item2, f, dT, newScaleMult,
                                                        out pairCashUsd, out pairCashBtc);

                    pnlIsCorrect &= localRes;
                    cashDollars  += pairCashUsd.CashUsd;
                    pnlDollars   += pairCashUsd.PnlUsd;
                    cashBtc      += pairCashBtc.CashBtc;
                    pnlBtc       += pairCashBtc.PnlBtc;
                }

                // Профиль позиции будет рисоваться только если ПНЛ был посчитан верно по ВСЕМ инструментам!
                if (pnlIsCorrect)
                {
                    InteractivePointLight ip;
                    // Показаны будут только узлы, совпадающие с реальными страйками.
                    // Потенциально это позволит сделать эти узлы пригодными для торговли по клику наподобие улыбки.
                    if (m_showNodes && tradableStrike)
                    {
                        // ReSharper disable once UseObjectOrCollectionInitializer
                        InteractivePointActive tmp = new InteractivePointActive();

                        tmp.IsActive = m_showNodes && tradableStrike;
                        string pnlUsdStr = (cashDollars + pnlDollars).ToString(m_tooltipFormat, CultureInfo.InvariantCulture);
                        string pnlBtcStr = (cashBtc + pnlBtc).ToString(DefaultBtcTooltipFormat, CultureInfo.InvariantCulture);
                        tmp.Tooltip = String.Format(CultureInfo.InvariantCulture, " F: {0}\r\n PnL($): {1}\r\n PnL(B): {2}", f, pnlUsdStr, pnlBtcStr);

                        // Если у нас получился сплайн по профилю позиции, значит мы можем вычислить дельту!
                        if (m_showNodes && tradableStrike)
                        {
                            // Готовим важные точки
                            var tuple = new Tuple <double, InteractivePointActive>(f, tmp);
                            deltaPoints.Add(tuple);
                        }

                        ip = tmp;
                    }
                    else
                    {
                        ip = new InteractivePointLight();
                    }

                    // PROD-6103 - Выводить профиль позиции в биткойнах
                    if (ProfileAsBtc)
                    {
                        ip.Value = new Point(f, cashBtc + pnlBtc);
                    }
                    else
                    {
                        ip.Value = new Point(f, cashDollars + pnlDollars);
                    }

                    controlPoints.Add(new InteractiveObject(ip));

                    xs.Add(f);
                    // PROD-6103 - Выводить профиль позиции в биткойнах
                    if (ProfileAsBtc)
                    {
                        ys.Add(cashBtc + pnlBtc);
                    }
                    else
                    {
                        ys.Add(cashDollars + pnlDollars);
                    }
                } // End if (pnlIsCorrect)
            }     // End foreach (var kvp in futPrices)

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

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

            try
            {
                if (xs.Count >= BaseCubicSpline.MinNumberOfNodes)
                {
                    SmileInfo info = new SmileInfo();
                    info.F            = oldInfo.F;
                    info.dT           = oldInfo.dT;
                    info.RiskFreeRate = oldInfo.RiskFreeRate;

                    NotAKnotCubicSpline spline = new NotAKnotCubicSpline(xs, ys);

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

                    res.Tag = info;

                    // Если у нас получился сплайн по профилю позиции, значит мы можем вычислить дельту!
                    for (int j = 1; j < deltaPoints.Count - 1; j++)
                    {
                        var    tuple = deltaPoints[j];
                        double f     = tuple.Item1;
                        var    ip    = tuple.Item2;

                        double actualDelta, deltaLeft, deltaRight;
                        if (m_twoSideDelta)
                        {
                            double prevF = deltaPoints[j - 1].Item1;
                            double nextF = deltaPoints[j + 1].Item1;

                            double currY = deltaPoints[j].Item2.ValueY;
                            double prevY = deltaPoints[j - 1].Item2.ValueY;
                            double nextY = deltaPoints[j + 1].Item2.ValueY;

                            deltaLeft  = (currY - prevY) / (f - prevF);
                            deltaRight = (nextY - currY) / (nextF - f);
                            // Считаем дельты слева и справа
                            // Мы передвинули улыбку в точку f и считаем дельту позиции В ЭТОЙ ЖЕ ТОЧКЕ(!)
                            //if (info.ContinuousFunction.TryGetValue(f - 100 * futStep, out deltaLeft) &&
                            //    info.ContinuousFunctionD1.TryGetValue(f + 100 * futStep, out deltaRight))
                            {
                                // Первый пробел уже учтен в Tooltip
                                ip.Tooltip = String.Format(CultureInfo.InvariantCulture, "{0}\r\n LeftD: {1:0.0}; RightD: {2:0.0}",
                                                           ip.Tooltip, deltaLeft, deltaRight);
                            }
                        }
                        else
                        {
                            // Мы передвинули улыбку в точку f и считаем дельту позиции В ЭТОЙ ЖЕ ТОЧКЕ(!)
                            if (info.ContinuousFunctionD1.TryGetValue(f, out actualDelta))
                            {
                                // Первый пробел уже учтен в Tooltip
                                ip.Tooltip = String.Format(CultureInfo.InvariantCulture, "{0}\r\n D: {1:0.0}", ip.Tooltip, actualDelta);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                m_context.Log(ex.ToString(), MessageType.Error, true);
                return(Constants.EmptySeries);
            }

            SetHandlerInitialized(now, true);

            return(res);
        }
Esempio n. 27
0
        public InteractiveSeries Execute(double time, InteractiveSeries smile, IOptionSeries optSer, int barNum)
        {
            InteractiveSeries res = new InteractiveSeries();
            int barsCount         = ContextBarsCount;

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

            double dT = time;

            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 (smile == null)
            {
                string msg = String.Format("[{0}] Argument 'smile' must be filled with InteractiveSeries.", GetType().Name);
                m_context.Log(msg, MessageType.Error, true);
                return(res);
            }

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

            if (oldInfo == null)
            {
                string msg = String.Format("[{0}] Property Tag of object smile must be filled with SmileInfo. Tag:{1}", GetType().Name, smile.Tag);
                m_context.Log(msg, MessageType.Error, true);
                return(res);
            }

            List <double> xs          = new List <double>();
            List <double> ys          = new List <double>();
            var           smilePoints = smile.ControlPoints;

            IOptionStrikePair[]      pairs         = optSer.GetStrikePairs().ToArray();
            PositionsManager         posMan        = PositionsManager.GetManager(m_context);
            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            foreach (InteractiveObject iob in smilePoints)
            {
                double rawTheta, f = iob.Anchor.ValueX;
                if (TryEstimateTheta(posMan, pairs, smile, m_greekAlgo, f, dT, m_tStep, out rawTheta))
                {
                    // Переводим тету в дифференциал 'изменение цены за 1 сутки'.
                    rawTheta = RescaleThetaToDays(m_tRemainMode, rawTheta);

                    // ReSharper disable once UseObjectOrCollectionInitializer
                    InteractivePointActive ip = new InteractivePointActive();
                    ip.IsActive = m_showNodes;
                    //ip.DragableMode = DragableMode.None;
                    //ip.Geometry = Geometries.Rect;
                    //ip.Color = System.Windows.Media.Colors.Green;
                    double y = rawTheta;
                    ip.Value = new Point(f, y);
                    string yStr = y.ToString(m_tooltipFormat, CultureInfo.InvariantCulture);
                    ip.Tooltip = String.Format(CultureInfo.InvariantCulture, "F:{0}; Th:{1}", f, yStr);

                    controlPoints.Add(new InteractiveObject(ip));

                    xs.Add(f);
                    ys.Add(y);
                }
            }

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

            try
            {
                if (xs.Count >= BaseCubicSpline.MinNumberOfNodes)
                {
                    // ReSharper disable once UseObjectOrCollectionInitializer
                    SmileInfo info = new SmileInfo();
                    info.F            = oldInfo.F;
                    info.dT           = oldInfo.dT;
                    info.RiskFreeRate = oldInfo.RiskFreeRate;

                    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);
        }
Esempio n. 28
0
        /// <summary>
        /// Метод под флаг TemplateTypes.INTERACTIVESPLINE
        /// </summary>
        public InteractiveSeries Execute(InteractiveSeries smile, IOptionSeries optSer, InteractiveSeries quoteIv, 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;

            // 1. Формируем маркеры заявок
            List <InteractiveObject> controlPoints          = new List <InteractiveObject>();
            PositionsManager         posMan                 = PositionsManager.GetManager(m_context);
            IList <PositionsManager.IvTargetInfo> ivTargets = posMan.GetIvTargets(m_isLong, true);

            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 <= k);
                if ((ivTarget.SecInfo.StrikeType != null) &&
                    (ivTarget.SecInfo.StrikeType.Value != StrikeType.Any))
                {
                    isCall = (ivTarget.SecInfo.StrikeType.Value == StrikeType.Call);
                }
                StrikeType optionType = isCall ? StrikeType.Call : StrikeType.Put;
                Contract.Assert(pair.Tick < 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 += 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;
                }

                // Пересчитываем сигму обратно, ЕСЛИ мы применили сдвиг цены в абсолютном выражении
                if (ivTarget.EntryShiftPrice != 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;
                    }
                }

                double totalQty;
                if (isCall)
                {
                    totalQty = posMan.GetTotalQty(pair.Call.Security, m_context.BarsCount, TotalProfitAlgo.AllPositions, ivTarget.IsLong);
                }
                else
                {
                    totalQty = posMan.GetTotalQty(pair.Put.Security, m_context.BarsCount, TotalProfitAlgo.AllPositions, ivTarget.IsLong);
                }
                double targetQty = Math.Abs(ivTarget.TargetShares) - totalQty;

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

                // Попробуем по-простому?
                tmp.Tag = ivTarget;

                tmp.IsActive     = true;
                tmp.ValueX       = k;
                tmp.ValueY       = sigma;
                tmp.DragableMode = DragableMode.None;
                if (ivTarget.EntryShiftPrice == 0)
                {
                    tmp.Tooltip = String.Format(CultureInfo.InvariantCulture,
                                                " F: {0}\r\n K: {1}; IV: {2:P2}\r\n {3} px {4} rIV {5:P2} @ {6}",
                                                futPx, k, sigma, optionType, theorOptPxBitcoins, ivTarget.EntryIv, targetQty);
                }
                else
                {
                    string shiftStr = (ivTarget.EntryShiftPrice > 0) ? "+" : "-";
                    shiftStr    = shiftStr + Math.Abs(ivTarget.EntryShiftPrice) + "ps";
                    tmp.Tooltip = String.Format(CultureInfo.InvariantCulture,
                                                " F: {0}\r\n K: {1}; IV: {2:P2}\r\n {3} px {4} rIV {5:P2} {6} @ {7}",
                                                futPx, k, sigma, optionType, theorOptPxBitcoins, ivTarget.EntryIv, shiftStr, targetQty);
                }

                //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
            InteractiveSeries res = new InteractiveSeries(); // Здесь так надо -- мы делаем новую улыбку

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

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

                m_clickableSeries = res;
            }

            return(res);
        }
        public InteractiveSeries Execute(double price, double time, InteractiveSeries smile, 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);

            double futPx = price;
            double dT    = time;

            if (!DoubleUtil.IsPositive(dT))
            {
                // [{0}] Time to expiry must be positive value. dT:{1}
                string msg = RM.GetStringFormat("OptHandlerMsg.TimeMustBePositive", GetType().Name, dT);
                if (wasInitialized)
                {
                    m_context.Log(msg, MessageType.Error, false);
                }
                return(Constants.EmptySeries);
            }

            if (!DoubleUtil.IsPositive(futPx))
            {
                // [{0}] Base asset price must be positive value. F:{1}
                string msg = RM.GetStringFormat("OptHandlerMsg.FutPxMustBePositive", GetType().Name, futPx);
                if (wasInitialized)
                {
                    m_context.Log(msg, MessageType.Error, false);
                }
                return(Constants.EmptySeries);
            }

            if (smile == null)
            {
                string msg = String.Format("[{0}] Argument 'smile' must be filled with InteractiveSeries.", GetType().Name);
                if (wasInitialized)
                {
                    m_context.Log(msg, MessageType.Error, false);
                }
                return(Constants.EmptySeries);
            }

            if (m_optionType == StrikeType.Any)
            {
                string msg = String.Format("[{0}] OptionType '{1}' is not supported.", GetType().Name, m_optionType);
                if (wasInitialized)
                {
                    m_context.Log(msg, MessageType.Error, false);
                }
                return(Constants.EmptySeries);
            }

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

            if (oldInfo == null)
            {
                string msg = String.Format("[{0}] Property Tag of object smile must be filled with SmileInfo. Tag:{1}", GetType().Name, smile.Tag);
                if (wasInitialized)
                {
                    m_context.Log(msg, MessageType.Error, false);
                }
                return(Constants.EmptySeries);
            }

            bool          isCall       = m_optionType == StrikeType.Call;
            double        putQty       = isCall ? 0 : m_fixedQty;
            double        callQty      = isCall ? m_fixedQty : 0;
            double        riskFreeRate = 0;
            List <double> xs           = new List <double>();
            List <double> ys           = new List <double>();
            var           smilePoints  = smile.ControlPoints;

            IOptionStrikePair[]      pairs         = optSer.GetStrikePairs().ToArray();
            PositionsManager         posMan        = PositionsManager.GetManager(m_context);
            List <InteractiveObject> controlPoints = new List <InteractiveObject>();

            foreach (IOptionStrikePair pair in pairs)
            {
                double rawTheta;
                if (TryEstimateTheta(putQty, callQty, optSer, pair, smile, m_greekAlgo, futPx, dT, m_tStep, riskFreeRate, out rawTheta))
                {
                    // Переводим тету в дифференциал 'изменение цены за 1 сутки'.
                    rawTheta /= OptionUtils.DaysInYear;

                    InteractivePointActive ip = new InteractivePointActive();
                    ip.IsActive = m_showNodes;
                    //ip.DragableMode = DragableMode.None;
                    //ip.Geometry = Geometries.Rect;
                    //ip.Color = System.Windows.Media.Colors.Green;
                    double y = rawTheta;
                    ip.Value = new Point(pair.Strike, y);
                    string yStr = y.ToString(m_tooltipFormat, CultureInfo.InvariantCulture);
                    ip.Tooltip = String.Format("K:{0}; Th:{1}", pair.Strike, yStr);

                    controlPoints.Add(new InteractiveObject(ip));

                    xs.Add(pair.Strike);
                    ys.Add(y);
                }
            }

            InteractiveSeries res = new InteractiveSeries(); // Здесь так надо -- мы делаем новую улыбку

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

            try
            {
                if (xs.Count >= BaseCubicSpline.MinNumberOfNodes)
                {
                    SmileInfo info = new SmileInfo();
                    info.F            = oldInfo.F;
                    info.dT           = oldInfo.dT;
                    info.RiskFreeRate = oldInfo.RiskFreeRate;

                    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);
            }

            SetHandlerInitialized(now);

            return(res);
        }
Esempio n. 30
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);
        }