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);
        }
Beispiel #2
0
        public InteractiveSeries Execute(double price, double time, IOptionSeries optSer, int barNum)
        {
            int barsCount = ContextBarsCount;

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

            double f  = 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);
                m_context.Log(msg, MessageType.Error, true);
                return(Constants.EmptySeries);
            }

            if (Double.IsNaN(f) || (f < Double.Epsilon))
            {
                // [{0}] Base asset price must be positive value. F:{1}
                string msg = RM.GetStringFormat("OptHandlerMsg.FutPxMustBePositive", GetType().Name, f);
                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 smileFunc = new SmileFunction3(m_ivAtm, m_shift, m_depth, f, dT);

            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("[WARNING:{0}] optSer must contain few strike pairs. pairs.Length:{1}", GetType().Name, pairs.Length);
                m_context.Log(msg, MessageType.Warning, true);
                return(Constants.EmptySeries);
            }

            double minK = pairs[0].Strike;
            double dK   = pairs[1].Strike - pairs[0].Strike;

            // Generate left invisible tail
            if (m_generateTails)
            {
                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 < m_minStrike) || (m_maxStrike < pair.Strike))
                {
                    showPoint = false;
                }

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

                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 <= f) // Puts
                    {
                        FillNodeInfo(ip, f, dT, pair, StrikeType.Put, OptionPxMode.Mid, sigma, false, m_isVisiblePoints);
                    }
                    else // Calls
                    {
                        FillNodeInfo(ip, f, dT, pair, StrikeType.Call, OptionPxMode.Mid, sigma, false, m_isVisiblePoints);
                    }
                }

                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)
            {
                AppendRightTail(smileFunc, xs, ys, maxK, dK, false);
            }

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

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

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

            res.Tag = info;

            return(res);
        }