/// <summary> /// Вычисление нескольких видов наклона улыбки и обновление исторической серии, /// которая потенциально может быть сохранена в глобальный кеш. /// При записи в кеш серия помещается в NotClearableContainer, чтобы выживать при очистке памяти. /// </summary> public static bool TryCalcAndWriteSkews(IContext context, NotAKnotCubicSpline smileSpline, bool useGlobal, bool allowGlobalWrite, int savePeriod, string futSymbol, DateTime optExpiry, double futPx, DateTime lastBarDate, TimeRemainMode tRemainMode, double plainTimeAsYears, double timeAsYears) { bool successSkew = false; var splineD1 = smileSpline.DeriveD1(); if (splineD1.TryGetValue(futPx, out var skewAtm)) { //string symbol = optSer.UnderlyingAsset.Symbol; // А. Записываем в Глобальный Кеш РАЗМЕРНЫЙ наклон (модель времени неважна) { string skewKey = IvOnF.GetSkewCashKey(futSymbol, optExpiry, SmileSkewMode.RawSkew, TimeRemainMode.PlainCalendar); var ivSkews = LoadOrCreateHistoryDict(context, useGlobal, skewKey); // Это просто запись на диск. К успешности вычисления наклона successSkew отношения не имеет successSkew = TryWrite(context, useGlobal, allowGlobalWrite, savePeriod, skewKey, ivSkews, lastBarDate, skewAtm); } // В. Записываем в Глобальный Кеш БЕЗРАЗМЕРНЫЙ наклон В БИРЖЕВОМ ВРЕМЕНИ (PlainCalendar) { double dSigmaDxExchange = SmileImitation5.GetDSigmaDx(futPx, plainTimeAsYears, skewAtm, 0); if (!DoubleUtil.IsNaN(dSigmaDxExchange)) { string skewKey = IvOnF.GetSkewCashKey(futSymbol, optExpiry, SmileSkewMode.ExchangeSkew, TimeRemainMode.PlainCalendar); var ivSkews = LoadOrCreateHistoryDict(context, useGlobal, skewKey); // Это просто запись на диск. К успешности вычисления наклона successSkew отношения не имеет successSkew = TryWrite(context, useGlobal, allowGlobalWrite, savePeriod, skewKey, ivSkews, lastBarDate, dSigmaDxExchange); } } // Д. Записываем в Глобальный Кеш БЕЗРАЗМЕРНЫЙ наклон В НАШЕМ ВРЕМЕНИ (в соответствии с tRemainMode) { double dSigmaDxRescaled = SmileImitation5.GetDSigmaDx(futPx, timeAsYears, skewAtm, 0); if (!DoubleUtil.IsNaN(dSigmaDxRescaled)) { string skewKey = IvOnF.GetSkewCashKey(futSymbol, optExpiry, SmileSkewMode.RescaledSkew, tRemainMode); var ivSkews = LoadOrCreateHistoryDict(context, useGlobal, skewKey); // Это просто запись на диск. К успешности вычисления наклона successSkew отношения не имеет successSkew = TryWrite(context, useGlobal, allowGlobalWrite, savePeriod, skewKey, ivSkews, lastBarDate, dSigmaDxRescaled); } } } // End if (splineD1.TryGetValue(futPx, out var skewAtm)) return(successSkew); }
private IList <double> PrepareData(ISecurity sec, string expiryDate) { DateTime expiry; if ((!DateTime.TryParseExact(expiryDate, IvOnF.DateFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out expiry)) && (!DateTime.TryParseExact(expiryDate, IvOnF.DateFormat + " HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out expiry))) { string msg = String.Format("[{0}.{1}.PrepareData] Unable to parse expiration date '{2}'. Expected date format '{3}'.", Context.Runtime.TradeName, GetType().Name, expiryDate, IvOnF.DateFormat); m_context.Log(msg, MessageType.Warning, true); return(Constants.EmptyListDouble); } //// и тут я понял, что дату экспирации в любом случае надо задавать руками... //string cashKey = typeof(IvOnF).Name + "_ivExchangeSigmas_" + sec.Symbol + "_" + // expiryDate.Replace(':', '-'); string skewKey = IvOnF.GetSkewCashKey(sec.Symbol, expiry, SkewMode, DistanceMode); Dictionary <DateTime, double> ivSkews = null; try { object globalObj = Context.LoadGlobalObject(skewKey, true); ivSkews = globalObj as Dictionary <DateTime, double>; // PROD-3970 - 'Важный' объект if (ivSkews == null) { var container = globalObj as NotClearableContainer; if ((container != null) && (container.Content != null)) { ivSkews = container.Content as Dictionary <DateTime, double>; } } } catch (NotSupportedException nse) { string fName = "", path = ""; if (nse.Data["fName"] != null) { fName = nse.Data["fName"].ToString(); } if (nse.Data["path"] != null) { path = nse.Data["path"].ToString(); } string msg = String.Format("[{0}.PrepareData] {1} when loading 'ivSkews' from global cache. cashKey: {2}; Message: {3}\r\n\r\nfName: {4}; path: {5}\r\n\r\n{6}", GetType().Name, nse.GetType().FullName, skewKey, nse.Message, fName, path, nse); m_context.Log(msg, MessageType.Warning, true); } catch (Exception ex) { string msg = String.Format("[{0}.PrepareData] {1} when loading 'ivSkews' from global cache. cashKey: {2}; Message: {3}\r\n\r\n{4}", GetType().Name, ex.GetType().FullName, skewKey, ex.Message, ex); m_context.Log(msg, MessageType.Warning, true); } if (ivSkews == null) { // Данного ключа в глобальном кеше нет? Тогда выход. // [{0}.PrepareData] There is no Skew ATM in global cache. Probably, you have to start agent 'Collect IV (ALL)' for security '{1}'. string msg = RM.GetStringFormat("OptHandlerMsg.GlobalSkewOnF.CacheNotFound", GetType().Name, expiryDate, sec); if (m_context.Runtime.IsAgentMode && (!m_ignoreCacheError)) { throw new ScriptException(msg); // PROD-4624 - Андрей велит кидать исключение. } bool isExpired = true; if (m_context.Runtime.IsAgentMode) { int amount = sec.Bars.Count; DateTime today = (amount > 0) ? sec.Bars[amount - 1].Date : new DateTime(); isExpired = expiry.Date.AddDays(1) < today.Date; } // А если в режиме лаборатории, тогда только жалуемся и продолжаем. m_context.Log(msg, MessageType.Warning, !isExpired); // Если серия уже умерла, пишем только в локальный лог return(Constants.EmptyListDouble); } List <double> res = new List <double>(); int len = sec.Bars.Count; if (len <= 0) { return(res); } int oldResLen = res.Count; double prevSkew = Double.NaN; for (int j = oldResLen; j < len; j++) { DateTime now = sec.Bars[j].Date; double skew; if (ivSkews.TryGetValue(now, out skew) && (!DoubleUtil.IsNaN(skew))) { prevSkew = skew; res.Add(skew); } else { if (m_repeatLastIv) { if (!Double.IsNaN(prevSkew)) { skew = prevSkew; } else { skew = Constants.NaN; if (j == 0) { #region Отдельно обрабатываю нулевой бар double tmp = Double.NaN; DateTime foundKey = new DateTime(1, 1, 1); // [2016-01-19] Когда история становится слишком длинной, это может вызывать проблемы // при итерировании в foreach. Потому что другой поток может в этот момент добавить новую точку в коллекцию. int repeat = 7; while (repeat > 0) { tmp = Double.NaN; foundKey = new DateTime(1, 1, 1); try { lock (ivSkews) { foreach (var kvp in ivSkews) { if (kvp.Key > now) { continue; } if (foundKey < kvp.Key) { foundKey = kvp.Key; tmp = kvp.Value; } } } repeat = -100; } catch (InvalidOperationException invOpEx) { repeat--; Thread.Sleep(10); if (repeat <= 0) { string msg = String.Format("[{0}.PrepareData] {1} when iterate through 'ivSkews'. cashKey: {2}; Message: {3}\r\n\r\n{4}", GetType().Name, invOpEx.GetType().FullName, skewKey, invOpEx.Message, invOpEx); m_context.Log(msg, MessageType.Warning, true); throw; } } } if ((foundKey.Year > 1) && DoubleUtil.IsPositive(tmp)) { skew = tmp; prevSkew = skew; } #endregion Отдельно обрабатываю нулевой бар } } res.Add(skew); } else { res.Add(Constants.NaN); } } } return(res); }