/// <summary> /// Обработчик под тип входных данных OPTION_SERIES /// </summary> public IList <double> Execute(IOptionSeries optSer) { if (optSer == null) { string msg = "[IV ATM] (optSer == null)"; m_context.Log(msg, MessageType.Warning, false); return(Constants.EmptyListDouble); } 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 List <double> res; ISecurity sec = optSer.UnderlyingAsset; int len = sec.Bars.Count; if (len <= 0) { return(Constants.EmptyListDouble); } if (m_context.IsFixedBarsCount) { #region Ветка с ФИКСИРОВАННЫМ количеством баров double lastIv = Double.NaN; res = new List <double>(len); for (int j = 0; j < len; j++) { DateTime now = sec.Bars[j].Date; double iv; if ((ivSigmas.TryGetValue(now, out iv)) && (!Double.IsNaN(iv)) && (iv > 0)) { lastIv = iv; res.Add(iv); } else { if (m_repeatLastIv && (!Double.IsNaN(lastIv))) { res.Add(lastIv); } else { res.Add(Constants.NaN); } } } #endregion Ветка с ФИКСИРОВАННЫМ количеством баров } else { #region Ветка с нарастающим количеством баров res = LocalHistory; // PROD-1933 // 1. Выполняю очистку локального кеша в сценарии восстановления соединения после дисконнекта if (res.Count > len) { res.Clear(); } // 2. Ищу последнее валидное значение в кеше причем только если это может быть нужно double lastIv = Double.NaN; if (m_repeatLastIv) { for (int j = res.Count - 1; j >= 0; j--) { if ((!Double.IsNaN(res[j])) && (res[j] > 0)) { lastIv = res[j]; break; } } } for (int j = res.Count; j < len; j++) { DateTime now = sec.Bars[j].Date; double iv; if ((ivSigmas.TryGetValue(now, out iv)) && (!Double.IsNaN(iv)) && (iv > 0)) { lastIv = iv; res.Add(iv); } else { if (m_repeatLastIv && (!Double.IsNaN(lastIv))) { res.Add(lastIv); } else { res.Add(Constants.NaN); } } } #endregion Ветка с нарастающим количеством баров } Debug.Assert(res != null, "How is it possible (res == null)?"); Debug.Assert(res.Count == len, String.Format("Wrong res.Count. res.Count:{0}; expected len:{1}; IsFixedBarsCount:{2}", res.Count, len, m_context.IsFixedBarsCount)); FinInfo baseFinInfo = optSer.UnderlyingAsset.FinInfo; // Эта проверка намекает на проблемы с маркет-датой. if (baseFinInfo.LastPrice == null) { string msg = "[IV ATM] (baseFinInfo.LastPrice == null)"; m_context.Log(msg, MessageType.Warning, false); return(res); } try { double sigma; double futPx = baseFinInfo.LastPrice.Value; NotAKnotCubicSpline spline = PrepareExchangeSmileSpline(optSer, Double.MinValue, Double.MaxValue); if ((spline != null) && spline.TryGetValue(futPx, out sigma) && DoubleUtil.IsPositive(sigma)) { DateTime lastBarDate = sec.Bars[len - 1].Date; 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 отношения не имеет bool success = TryWrite(m_context, UseGlobalCache, AllowGlobalReadWrite, GlobalSavePeriod, cashKey, ivSigmas, lastBarDate, sigma); // Теперь надо вычислить безразмерный наклон кодом в классе SmileImitation5 bool successSkew = TryCalcAndWriteSkews(m_context, spline, UseGlobalCache, AllowGlobalReadWrite, GlobalSavePeriod, optSer.UnderlyingAsset.Symbol, expiry, futPx, lastBarDate, m_tRemainMode, plainTimeAsYears, timeAsYears); } else { // Если перемасштабировать улыбку не получается придется эту точку проигнорировать // Надо ли сделать соответствующую запись в логе??? sigma = Constants.NaN; } #endregion Зверская ветка по замене времени } else { // Это просто запись на диск. К успешности вычисления волы success отношения не имеет bool success = TryWrite(m_context, UseGlobalCache, AllowGlobalReadWrite, GlobalSavePeriod, cashKey, ivSigmas, lastBarDate, sigma); } } else { sigma = Constants.NaN; } res[len - 1] = sigma; } catch (Exception ex) { m_context.Log(ex.ToString(), MessageType.Error, false); return(res); } if (m_repeatLastIv) { if (DoubleUtil.AreClose(res[len - 1], Constants.NaN) || Double.IsNaN(res[len - 1]) || (res[len - 1] <= 0)) { // Итерируюсь с конца в начало пока не найду последний ненулевой элемент. // Использую его в качестве ВСЕХ последних значений ряда. for (int j = len - 1; j >= 0; j--) { if ((!DoubleUtil.AreClose(res[j], Constants.NaN)) && (!Double.IsNaN(res[j])) && (res[j] > 0)) { double lastIv = res[j]; for (int k = j + 1; k < len; k++) { res[k] = lastIv; } break; } } } } return(new ReadOnlyCollection <double>(res)); }
/// <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 } } }
private double EstimateTimeForGivenBar(IOption opt, ISecurity sec, DateTime now, DateTime prevBarDate, DateTime prevExpDate, out double timeAsDays, out double timeAsYears, out DateTime barDate, out DateTime expDate) { DateTime curDate; #region Get current date switch (m_dateMode) { case CurrentDateMode.FixedDate: curDate = m_fixedDate; break; case CurrentDateMode.CurrentDate: curDate = now; break; case CurrentDateMode.Tomorrow: curDate = now.AddDays(1); break; case CurrentDateMode.NextWorkingDay: curDate = now.AddDays(1); while (!CalendarWithoutHolidays.Russia.IsWorkingDay(curDate)) { curDate = curDate.AddDays(1); } break; case CurrentDateMode.NextWeek: curDate = now.AddDays(7); break; default: throw new NotImplementedException("CurDateMode:" + m_dateMode); } #endregion Get current date //DateTime today = sec.Bars[j].Date; DateTime today = now.Date; // Если дата прежняя, то и дата экспирации ещё не должна измениться if (today == prevBarDate) { barDate = today; expDate = prevExpDate; } //else if ((prevExpDate - prevBarDate).TotalDays > 1) // А если бары недельные??? или месячные??? else { barDate = today; #region Get expiration date switch (m_expiryMode) { case ExpiryMode.FixedExpiry: expDate = m_expirationDate; break; case ExpiryMode.FirstExpiry: { if (opt == null) { expDate = sec.SecurityDescription.ExpirationDate; } else { IOptionSeries optSer = (from ser in opt.GetSeries() where (today <= ser.ExpirationDate.Date) orderby ser.ExpirationDate ascending select ser).FirstOrDefault(); // Если все серии уже умерли, вернуть последнюю, чтобы гарантировать возврат даты if (optSer == null) { optSer = (from ser in opt.GetSeries() orderby ser.ExpirationDate descending select ser).First(); } expDate = optSer.ExpirationDate; } } break; case ExpiryMode.LastExpiry: { if (opt == null) { expDate = sec.SecurityDescription.ExpirationDate; } else { IOptionSeries optSer = (from ser in opt.GetSeries() where (today <= ser.ExpirationDate.Date) orderby ser.ExpirationDate descending select ser).FirstOrDefault(); // Если все серии уже умерли, вернуть последнюю, чтобы гарантировать возврат даты if (optSer == null) { optSer = (from ser in opt.GetSeries() orderby ser.ExpirationDate descending select ser).First(); } expDate = optSer.ExpirationDate; } } break; case ExpiryMode.ExpiryByNumber: { if (opt == null) { expDate = sec.SecurityDescription.ExpirationDate; } else { IOptionSeries[] optSers = (from ser in opt.GetSeries() where (today <= ser.ExpirationDate.Date) orderby ser.ExpirationDate ascending select ser).ToArray(); int ind = Math.Min(m_seriesIndex - 1, optSers.Length - 1); ind = Math.Max(ind, 0); IOptionSeries optSer; // Если все серии уже умерли, вернуть последнюю, чтобы гарантировать возврат даты if (optSers.Length == 0) { optSer = (from ser in opt.GetSeries() orderby ser.ExpirationDate descending select ser).First(); } else { optSer = optSers[ind]; } expDate = optSer.ExpirationDate; } } break; default: throw new NotImplementedException("ExpirationMode:" + m_expiryMode); } #endregion Get expiration date } // Грубое решение для определения точного времени экспирации if (m_expiryMode != ExpiryMode.FixedExpiry) { expDate = expDate.Date + m_expirationTime; } // Просто сдвигаю текущую дату? double time = TimeToExpiry.GetDt(expDate, curDate + m_dateShift, m_tRemainMode, m_useDays, out timeAsDays, out timeAsYears); return(time); }
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); }