/// <summary> /// Обработчик под тип входных данных OPTION_SERIES /// </summary> public double Execute(IOptionSeries optSer, int barNum) { double failRes = Constants.NaN; if (m_repeatLastIv) { failRes = Double.IsNaN(m_prevIv) ? Constants.NaN : m_prevIv; } Dictionary <DateTime, double> ivSigmas; #region Get cache DateTime expiry = optSer.ExpirationDate.Date; string cashKey = IvOnF.GetCashKey(optSer.UnderlyingAsset.Symbol, expiry, m_rescaleTime, m_tRemainMode); ivSigmas = LoadOrCreateHistoryDict(UseGlobalCache, cashKey); #endregion Get cache ISecurity sec = optSer.UnderlyingAsset; int len = sec.Bars.Count; if (len <= 0) { return(failRes); } DateTime lastBarDate = sec.Bars[barNum].Date; double iv; if ((ivSigmas.TryGetValue(lastBarDate, out iv)) && (!Double.IsNaN(iv)) && (iv > 0)) { m_prevIv = iv; return(iv); } else { int barsCount = ContextBarsCount; if (barNum < barsCount - 1) { // Если история содержит осмысленное значение, то оно уже содержится в failRes return(failRes); } else { #region Process last bar(s) FinInfo baseFinInfo = optSer.UnderlyingAsset.FinInfo; if (baseFinInfo.LastPrice == null) { string msg = "[IV ATM 2] (baseFinInfo.LastPrice == null)"; m_context.Log(msg, MessageType.Warning, false); return(failRes); } double futPx = baseFinInfo.LastPrice.Value; if (futPx <= Double.Epsilon) { return(failRes); } NotAKnotCubicSpline spline = null; try { spline = IvOnF.PrepareExchangeSmileSpline(optSer, Double.MinValue, Double.MaxValue); } catch (ScriptException scriptEx) { m_context.Log(scriptEx.ToString(), MessageType.Error, false); return(failRes); } catch (Exception ex) { m_context.Log(ex.ToString(), MessageType.Error, false); return(failRes); } if (spline == null) { return(failRes); } try { double sigma; if (spline.TryGetValue(futPx, out sigma) && (sigma > 0)) { if (m_rescaleTime) { #region Зверская ветка по замене времени double ivAtm = sigma; DateTime expDate = optSer.ExpirationDate.Date + m_expiryTime; DateTime now = baseFinInfo.LastUpdate; // 1. Надо перевести волатильность в абсолютную цену // с учетом плоского календарного времени применяемого РТС double plainTimeAsYears; { double plainTimeAsDays; TimeToExpiry.GetDt(expDate, now, TimeRemainMode.PlainCalendar, false, out plainTimeAsDays, out plainTimeAsYears); } // 2. Вычисляем 'нормальное' время double timeAsDays, timeAsYears; TimeToExpiry.GetDt(expDate, now, m_tRemainMode, false, out timeAsDays, out timeAsYears); sigma = FinMath.RescaleIvToAnotherTime(plainTimeAsYears, ivAtm, timeAsYears); if (DoubleUtil.IsPositive(sigma)) { // Это просто запись на диск. К успешности вычисления волы success отношения не имеет lock (ivSigmas) { bool success = IvOnF.TryWrite(m_context, UseGlobalCache, AllowGlobalReadWrite, GlobalSavePeriod, cashKey, ivSigmas, lastBarDate, sigma); m_prevIv = sigma; // Теперь надо вычислить безразмерный наклон кодом в классе SmileImitation5 bool successSkew = IvOnF.TryCalcAndWriteSkews(m_context, spline, UseGlobalCache, AllowGlobalReadWrite, GlobalSavePeriod, optSer.UnderlyingAsset.Symbol, expiry, futPx, lastBarDate, m_tRemainMode, plainTimeAsYears, timeAsYears); return(sigma); } } else { // Если перемасштабировать улыбку не получается придется эту точку проигнорировать // Надо ли сделать соответствующую запись в логе??? sigma = Constants.NaN; } #endregion Зверская ветка по замене времени } else { lock (ivSigmas) { bool success = IvOnF.TryWrite(m_context, UseGlobalCache, AllowGlobalReadWrite, GlobalSavePeriod, cashKey, ivSigmas, lastBarDate, sigma); m_prevIv = sigma; return(sigma); } } } } catch (Exception ex) { m_context.Log(ex.ToString(), MessageType.Error, false); } return(failRes); #endregion Process last bar } } }
public void Execute(double price, double time, IOptionSeries optSer, ICanvasPane pane, int barNum) { int barsCount = ContextBarsCount; if ((barNum < barsCount - 1) || (optSer == null)) { return; } // PROD-3577 pane.FeetToBorder2ByDefault = true; double futPx = price; double dT = time; if (!DoubleUtil.IsPositive(futPx)) { return; } if (!DoubleUtil.IsPositive(dT)) { return; } double sigma; IFunction smileFunc = IvOnF.PrepareExchangeSmileSpline(optSer, Double.MinValue, Double.MaxValue); if ((smileFunc == null) || (!smileFunc.TryGetValue(futPx, out sigma)) || (!DoubleUtil.IsPositive(sigma))) { //При работе с Эксанте и прочим Западом Биржевой улыбки не будет //Поэтому надо иметь 'План Б': подставить фиксированную волатильность 30%! sigma = DefaultSigma; // PROD-5968 - У биткойна совсем другой типичный уровень волатильности var parent = optSer.UnderlyingAsset; var secDesc = parent.SecurityDescription; var tp = secDesc.TradePlace; var dsClassName = tp?.DataSource?.GetType().Name; if (dsClassName == "DeribitDS") { sigma = DefaultSigmaDeribit; } else if (dsClassName == "ExanteDataSource") { if (tp.Id == "CME") { if (secDesc.ActiveType.IsFuture() && parent.Symbol.StartsWith("ES")) { sigma = DefaultSigmaEs; } } } } if (pane != null) { string expiryStr = optSer.ExpirationDate.ToString(TimeToExpiry.DateTimeFormat, CultureInfo.InvariantCulture); Rect rect = PrepareVieportSettings(expiryStr, futPx, dT, sigma); ApplySettings(pane, rect); if (ManageXGridStep) { var pairs = optSer.GetStrikePairs().ToArray(); int pLen = pairs.Length; if (pLen > 1) { double dK = pairs[1].Strike - pairs[0].Strike; if (pLen > 2) { int t = pLen / 2; // Делим нацело. Для pLen==3 получаем 1 dK = pairs[t + 1].Strike - pairs[t].Strike; } pane.XAxisStep = GetXAxisStep(dK); pane.XAxisDiviser = GetXAxisDivisor(dK); } } } }
private bool TryProcessSeries(IOptionSeries optSer, DateTime now, out double ivAtm) { ivAtm = Constants.NaN; if (optSer == null) { return(false); } Dictionary <DateTime, double> ivSigmas; #region Get cache DateTime expiry = optSer.ExpirationDate.Date; string cashKey = IvOnF.GetCashKey(optSer.UnderlyingAsset.Symbol, expiry, m_rescaleTime, m_tRemainMode); object globalObj = Context.LoadGlobalObject(cashKey, true); ivSigmas = globalObj as Dictionary <DateTime, double>; // PROD-3970 - 'Важный' объект if (ivSigmas == null) { var container = globalObj as NotClearableContainer; if ((container != null) && (container.Content != null)) { ivSigmas = container.Content as Dictionary <DateTime, double>; } } if (ivSigmas == null) { ivSigmas = new Dictionary <DateTime, double>(); } #endregion Get cache ISecurity sec = optSer.UnderlyingAsset; int len = sec.Bars.Count; if (len <= 0) { return(false); } FinInfo baseFinInfo = optSer.UnderlyingAsset.FinInfo; if (baseFinInfo.LastPrice == null) { string msg = "[IV ATM (all series)] (baseFinInfo.LastPrice == null)"; m_context.Log(msg, MessageType.Warning, false); return(false); } double futPx = baseFinInfo.LastPrice.Value; if (futPx <= Double.Epsilon) { return(false); } NotAKnotCubicSpline spline = null; try { spline = IvOnF.PrepareExchangeSmileSpline(optSer, Double.MinValue, Double.MaxValue); } catch (ScriptException scriptEx) { m_context.Log(scriptEx.ToString(), MessageType.Error, false); return(false); } catch (Exception ex) { m_context.Log(ex.ToString(), MessageType.Error, false); return(false); } if (spline == null) { return(false); } try { double sigma; if (spline.TryGetValue(futPx, out sigma) && (!Double.IsNaN(sigma)) && (sigma > 0)) { ivAtm = sigma; DateTime lastBarDate = sec.Bars[len - 1].Date; if (m_rescaleTime) { #region Зверская ветка по замене времени DateTime expDate = optSer.ExpirationDate.Date + m_expiryTime; // 1. Надо перевести волатильность в абсолютную цену // с учетом плоского календарного времени применяемого РТС double plainTimeAsYears; { double plainTimeAsDays; TimeToExpiry.GetDt(expDate, now, TimeRemainMode.PlainCalendar, false, out plainTimeAsDays, out plainTimeAsYears); } // 2. Вычисляем 'нормальное' время double timeAsDays, timeAsYears; TimeToExpiry.GetDt(expDate, now, m_tRemainMode, false, out timeAsDays, out timeAsYears); sigma = FinMath.RescaleIvToAnotherTime(plainTimeAsYears, ivAtm, timeAsYears); if (DoubleUtil.IsPositive(sigma)) { ivAtm = sigma; // Это просто запись на диск. К успешности вычисления волы success отношения не имеет bool success = IvOnF.TryWrite(m_context, true, true, 1, cashKey, ivSigmas, lastBarDate, sigma); // Теперь надо вычислить безразмерный наклон кодом в классе SmileImitation5 bool successSkew = IvOnF.TryCalcAndWriteSkews(m_context, spline, true, true, 1, optSer.UnderlyingAsset.Symbol, expiry, futPx, lastBarDate, m_tRemainMode, plainTimeAsYears, timeAsYears); return(true); } else { // Если перемасштабировать улыбку не получается придется эту точку проигнорировать // Надо ли сделать соответствующую запись в логе??? return(false); } #endregion Зверская ветка по замене времени } else { // Это просто запись на диск. К успешности вычисления волы success отношения не имеет bool success = IvOnF.TryWrite(m_context, true, true, 1, cashKey, ivSigmas, lastBarDate, sigma); return(true); } } } catch (ScriptException scriptEx) { m_context.Log(scriptEx.ToString(), MessageType.Error, false); } catch (Exception ex) { m_context.Log(ex.ToString(), MessageType.Error, false); //throw; } return(false); }