public double MakeDeal(ISecurity source, IOptionStrike strike, ISecurity priceSec, double strikePrice, bool signal, int barNum, bool isCall) { var optionLot = strike.LotTick; var strikeStep = strike.Tick; var sigma = GetVolatility(source)[barNum]; var ct = source.Bars[barNum].Date; var dT = ct.GetDt(Expiration); var price = priceSec.Bars[barNum].Close; var optPx = strikePrice.GetOptPx(strikeStep, isCall, price, dT, sigma); if (!signal) { return(optPx); } var prefix = isCall ? 'C' : 'P'; var name = $"{prefix}{ExpPrefix}{strikePrice:0}"; var oldPos = source.Positions.GetLastActiveForSignal(name, barNum); if (oldPos == null) { source.Positions.MakeVirtualPosition(barNum + 1, optionLot, optPx, name); } else { var shares = oldPos.GetShares(barNum); if (shares < MaxShares && oldPos.GetPositionLastPrice(barNum) > optPx) { oldPos.VirtualChange(barNum + 1, optPx, shares + optionLot, $"C-{name}"); } } return(optPx); }
protected override void FillStrikeInfo(IOptionStrike optionStrike, StrikeInfo stInfo) { switch (optionStrike.StrikeType) { case StrikeType.Call: stInfo.Call = optionStrike.FinInfo.Ask ?? Constants.NaN; break; case StrikeType.Put: stInfo.Put = optionStrike.FinInfo.Ask ?? Constants.NaN; break; default: return; } }
/// <summary> /// Обработчик под тип входных данных OPTION_SERIES /// </summary> public IList <Double2> Execute(IOptionSeries optSer) { List <Double2> res = new List <Double2>(); IOptionStrike[] strikes = (from strike in optSer.GetStrikes() orderby strike.Strike ascending select strike).ToArray(); for (int j = 0; j < strikes.Length; j++) { IOptionStrike sInfo = strikes[j]; if ((sInfo.FinInfo == null) || (!sInfo.FinInfo.TheoreticalPrice.HasValue)) { continue; } double optPx = sInfo.FinInfo.TheoreticalPrice.Value; optPx *= m_multPx; optPx += m_addPx * sInfo.Security.SecurityDescription.GetTick(sInfo.FinInfo.TheoreticalPrice.Value); res.Add(new Double2(sInfo.Strike, optPx)); } return(res); }
/// <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); }
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); }
public Double2N Execute(IOptionStrike source) { var strikes = source != null ? new[] { source } : new IOptionStrike[0]; return(CalculateInternal(strikes)); }
protected abstract void FillStrikeInfo(IOptionStrike optionStrike, StrikeInfo stInfo);
/// <summary> /// Вычисление цены опциона различными способами. Есть возможность сразу сделать сдвиг цены (предусмотрены проверки). /// </summary> /// <param name="externalContext">Контекст блока для логгирования проблемы</param> /// <param name="f">Цена БА (нажна как верхняя оценка цены колла</param> /// <param name="sec">Инструмент</param> /// <param name="mode">алгоритм расчета (покупка, продажа, середина спреда)</param> /// <param name="shiftAsk">сдвиг асков</param> /// <param name="shiftBid">сдвиг бидов</param> /// <param name="qty">количество лотов в заявке</param> /// <param name="optTime">время получения этих котировок из рыночного провайдера</param> /// <returns>цена опциона (в случае проблем возвращает NaN)</returns> public static double GetOptPrice(IContext externalContext, double f, IOptionStrike sec, OptionPxMode mode, double shiftAsk, double shiftBid, out double qty, out DateTime optTime) { qty = Double.NaN; optTime = new DateTime(); double optPx = Double.NaN; // PROD-5952 - Не надо дергать стакан без нужды //sec.UpdateQueueData(); if (mode == OptionPxMode.Ask) { if (/* sec.FinInfo.AskSize.HasValue && */ sec.FinInfo.Ask.HasValue) { optPx = sec.FinInfo.Ask.Value; optTime = sec.FinInfo.LastUpdate; qty = 0; if (sec.FinInfo.AskSize.HasValue) { qty = sec.FinInfo.AskSize.Value; } else { // PROD-5952 - Не надо дергать стакан без нужды //// Аски отсортированы по возрастанию //var queue = sec.GetSellQueue(externalContext.BarsCount - 1); //if ((queue != null) && (queue.Count > 0)) //{ // IQueueData ask = queue[0]; // queue.First(); // qty = ask.Quantity; //} } } else { // PROD-5952 - Не надо дергать стакан без нужды #region Нет данных в FinInfo // // Аски отсортированы по возрастанию // var queue = sec.GetSellQueue(externalContext.BarsCount - 1); // if ((queue != null) && (queue.Count > 0)) // { // IQueueData ask = queue[0]; // queue.First(); //#if DEBUG // if (!s_conflictDate.ContainsKey(sec.Security.SecurityDescription.FullName)) // { // bool check = (ask.Security.FullName == sec.Security.SecurityDescription.FullName); // if (!check) // s_conflictDate[sec.Security.SecurityDescription.FullName] = ask.LastUpdate; // Debug.Assert(check, // String.Format("Expected security: {0}; actual security: {1}", // sec.Security.SecurityDescription.FullName, ask.Security.FullName)); // } //#endif // optPx = ask.Price; // qty = ask.Quantity; // optTime = ask.LastUpdate; // //string msg = // // String.Format( // // "[DEBUG:{0}] I was forced to use 'sec.GetSellQueue'. sec.Bars.Count:{1}; ask.LastUpdate:{2}; sec:{3}", // // typeof(IvSmile).Name, sec.Bars.Count, // // ask.LastUpdate.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture), // // sec); // //externalContext.Log(msg, MessageType.Warning, true); // } #endregion Нет данных в FinInfo } if (Double.IsNaN(optPx) || (optPx <= Double.Epsilon)) { optPx = 2 * f; // Это одна из верхних оценок цены опциона. } else { optPx += shiftAsk; } } else if (mode == OptionPxMode.Bid) { if (/* sec.FinInfo.BidSize.HasValue && */ sec.FinInfo.Bid.HasValue) { optPx = sec.FinInfo.Bid.Value; optTime = sec.FinInfo.LastUpdate; qty = 0; if (sec.FinInfo.BidSize.HasValue) { qty = sec.FinInfo.BidSize.Value; } else { // PROD-5952 - Не надо дергать стакан без нужды //// Биды отсортированы ПО УБЫВАНИЮ!!! //var queue = sec.GetBuyQueue(externalContext.BarsCount - 1); //if ((queue != null) && (queue.Count > 0)) //{ // IQueueData bid = queue[0]; // queue.First(); // qty = bid.Quantity; //} } } else { // PROD-5952 - Не надо дергать стакан без нужды #region Нет данных в FinInfo // // Биды отсортированы ПО УБЫВАНИЮ!!! // var queue = sec.GetBuyQueue(externalContext.BarsCount - 1); // if ((queue != null) && (queue.Count > 0)) // { // IQueueData bid = queue[0]; // queue.First(); //#if DEBUG // if (!s_conflictDate.ContainsKey(sec.Security.SecurityDescription.FullName)) // { // bool check = (bid.Security.FullName == sec.Security.SecurityDescription.FullName); // if (!check) // s_conflictDate[sec.Security.SecurityDescription.FullName] = bid.LastUpdate; // Debug.Assert(check, // String.Format("Expected security: {0}; actual security: {1}", // sec.Security.SecurityDescription.FullName, bid.Security.FullName)); // } //#endif // optPx = bid.Price; // qty = bid.Quantity; // optPx -= shiftBid; // optPx = Math.Max(optPx, 0); // optTime = bid.LastUpdate; // //string msg = // // String.Format( // // "[DEBUG:{0}] I was forced to use 'sec.GetSellQueue'. sec.Bars.Count:{1}; bid.LastUpdate:{2}; sec:{3}", // // typeof(IvSmile).Name, sec.Bars.Count, // // bid.LastUpdate.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture), // // sec); // //externalContext.Log(msg, MessageType.Warning, true); // } #endregion Нет данных в FinInfo } } else if (mode == OptionPxMode.Mid) { if (/* sec.FinInfo.BidSize.HasValue && */ sec.FinInfo.Bid.HasValue && /* sec.FinInfo.AskSize.HasValue && */ sec.FinInfo.Ask.HasValue) { double askPx = sec.FinInfo.Ask.Value; //double askQty = sec.FinInfo.AskSize.Value; if (Double.IsNaN(askPx) || (askPx <= Double.Epsilon)) { askPx = 2.0 * f; // Это одна из верхних оценок цены опциона. } else { askPx += shiftAsk; } double bidPx = sec.FinInfo.Bid.Value; //double bidQty = sec.FinInfo.BidSize.Value; bidPx -= shiftBid; bidPx = Math.Max(bidPx, 0); optPx = (askPx + bidPx) / 2.0; //qty = Math.Min(askQty, bidQty); double askQty = 0, bidQty = 0; #region AskQty if (sec.FinInfo.AskSize.HasValue) { askQty = sec.FinInfo.AskSize.Value; } else { // PROD-5952 - Не надо дергать стакан без нужды //// Аски отсортированы по возрастанию //var queue = sec.GetSellQueue(externalContext.BarsCount - 1); //if ((queue != null) && (queue.Count > 0)) //{ // IQueueData ask = queue[0]; // queue.First(); // askQty = ask.Quantity; //} } #endregion AskQty #region BidQty if (sec.FinInfo.BidSize.HasValue) { bidQty = sec.FinInfo.BidSize.Value; } else { // PROD-5952 - Не надо дергать стакан без нужды //// Биды отсортированы ПО УБЫВАНИЮ!!! //var queue = sec.GetBuyQueue(externalContext.BarsCount - 1); //if ((queue != null) && (queue.Count > 0)) //{ // IQueueData bid = queue[0]; // queue.First(); // bidQty = bid.Quantity; //} } #endregion BidQty qty = Math.Min(askQty, bidQty); optTime = sec.FinInfo.LastUpdate; } else { // PROD-5952 - Не надо дергать стакан без нужды #region Нет данных в FinInfo // var askQueue = sec.GetSellQueue(externalContext.BarsCount - 1); // var bidQueue = sec.GetBuyQueue(externalContext.BarsCount - 1); // if ((askQueue != null) && (askQueue.Count > 0) && // (bidQueue != null) && (bidQueue.Count > 0)) // { // // Аски отсортированы по возрастанию // IQueueData ask = askQueue[0]; // askQueue.First(); //#if DEBUG // if (!s_conflictDate.ContainsKey(sec.Security.SecurityDescription.FullName)) // { // bool check = (ask.Security.FullName == sec.Security.SecurityDescription.FullName); // if (!check) // s_conflictDate[sec.Security.SecurityDescription.FullName] = ask.LastUpdate; // Debug.Assert(check, // String.Format("Expected security: {0}; actual security: {1}", // sec.Security.SecurityDescription.FullName, ask.Security.FullName)); // } //#endif // double askPx = ask.Price; // double askQty = ask.Quantity; // if (Double.IsNaN(askPx) || (askPx <= Double.Epsilon)) // askPx = 2.0 * f; // Это одна из верхних оценок цены опциона. // else // askPx += shiftAsk; // // Биды отсортированы ПО УБЫВАНИЮ!!! // IQueueData bid = bidQueue[0]; // bidQueue.First(); //#if DEBUG // if (!s_conflictDate.ContainsKey(sec.Security.SecurityDescription.FullName)) // { // bool check = (bid.Security.FullName == sec.Security.SecurityDescription.FullName); // if (!check) // s_conflictDate[sec.Security.SecurityDescription.FullName] = bid.LastUpdate; // Debug.Assert(check, // String.Format("Expected security: {0}; actual security: {1}", // sec.Security.SecurityDescription.FullName, bid.Security.FullName)); // } //#endif // double bidPx = bid.Price; // double bidQty = bid.Quantity; // bidPx -= shiftBid; // bidPx = Math.Max(bidPx, 0); // optPx = (askPx + bidPx) / 2.0; // qty = Math.Min(askQty, bidQty); // optTime = (bid.LastUpdate < ask.LastUpdate) ? ask.LastUpdate : bid.LastUpdate; // } #endregion Нет данных в FinInfo } } else { throw new NotImplementedException("OptPxMode:" + mode); } return(optPx); }
public bool Equals(IOptionStrike optionStrike) { bool res = Equals(optionStrike.FinInfo.Security); return(res); }