public SecurityTSlab(ISecurity compressedSecurity, ISecurity baseSecurity) { this.baseSecurity = baseSecurity; finInfo = baseSecurity.FinInfo; InitializeSecurity(compressedSecurity); CompareBarsBaseSecurityWithCompressedSecurity(); }
public FinInfo GetDFNPDataByID(int DataCaptYM, string DeptId) { Dictionary <string, object> sqlParamDictionary = new Dictionary <string, object>(); sqlParamDictionary.Add("DataCaptYM", DataCaptYM); sqlParamDictionary.Add("DeptID", DeptId); IDbCommand command = new SqlCommand().GetCommandWithParameters(sqlParamDictionary, _SELECT_DFNP_Data); SqlConnection connection = DBConnectionHelper.OpenNewSqlConnection(this.ConnectionString); command.Connection = connection; FinInfo finInfo = EntityMapper.MapSingle <FinInfo>(command.ExecuteReader()); DBConnectionHelper.CloseSqlConnection(connection); return(finInfo); }
protected override double?GetValue(FinInfo finInfo) { if (finInfo == null || finInfo.Security == null) { return(1); } var lastPrice = finInfo.LastPrice ?? 0.0; var tick = finInfo.Security.GetTick(lastPrice); if (!DoubleUtil.IsPositive(tick)) { tick = Math.Pow(10, -finInfo.Security.Decimals); } return(tick); }
public void GetDFNPData(int _dataCaptYM) { FormsRepository formsRepository = new FormsRepository(); var DataCaptYM = SessionManager.DataCaptYR > 0 ? SessionManager.DataCaptYR : (_dataCaptYM > 0 ? _dataCaptYM : 0); string deptID = string.IsNullOrEmpty(SessionManager.EmpDeptID) ? SessionManager.DeptID : SessionManager.EmpDeptID; finInfo = formsRepository.GetDFNPDataByID(DataCaptYM, deptID); if (finInfo == null) { finInfo = new FinInfo(); } if (finInfo.DataStatus == 0) { finInfo.DataCaptYM = DataCaptYM; finInfo.DataStatus = (int)DataAccess.Enum.DataStatus.DataEntryStartedbyOperator; finInfo.DataStatusName = (DataAccess.Enum.DataStatus.DataEntryStartedbyOperator).GetStringValue(); } }
protected override double?GetValue(FinInfo finInfo) { return(finInfo.SellDeposit); }
protected override double?GetValue(FinInfo finInfo) { return(finInfo.BuyCount); }
protected abstract double?GetValue(FinInfo finInfo);
protected override bool TryCalculate(Dictionary <DateTime, double> history, DateTime now, int barNum, object[] args, out double val) { ISecurity sec = (ISecurity)args[0]; IOptionSeries optSer = (IOptionSeries)args[1]; val = Double.NaN; double px; #region switch(m_pxMode) switch (m_pxMode) { case BasePxMode.FixedPx: px = m_fixedPx; break; case BasePxMode.LastTrade: if (sec.FinInfo.LastPrice.HasValue) { px = sec.FinInfo.LastPrice.Value; } else { return(false); } break; case BasePxMode.BidAskMidPoint: { FinInfo info = sec.FinInfo; if (info.Ask.HasValue && info.Bid.HasValue && info.AskSize.HasValue && info.BidSize.HasValue && (info.AskSize.Value > 0) && (info.BidSize.Value > 0)) { px = (info.Ask.Value + info.Bid.Value) / 2; } else if (info.Ask.HasValue && info.AskSize.HasValue && (info.AskSize.Value > 0)) { px = info.Ask.Value; } else if (info.Bid.HasValue && info.BidSize.HasValue && (info.BidSize.Value > 0)) { px = info.Bid.Value; } else { // Приемлемо ли такое решение? if (info.LastPrice.HasValue) { px = info.LastPrice.Value; } else { return(false); } } } break; case BasePxMode.TheorPxBased: { if (optSer == null) { return(false); } IOptionStrikePair[] pairs = optSer.GetStrikePairs().ToArray(); IOptionStrikePair pair = pairs[pairs.Length / 2]; if ((pair.PutFinInfo.TheoreticalPrice == null) || (pair.CallFinInfo.TheoreticalPrice == null)) { return(false); } double putPx = pair.PutFinInfo.TheoreticalPrice.Value; double callPx = pair.CallFinInfo.TheoreticalPrice.Value; px = callPx - putPx + pair.Strike; } break; default: throw new NotImplementedException("pxMode:" + m_pxMode); } #endregion switch(m_pxMode) val = px; return(true); }
/// <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> /// Метод под флаг TemplateTypes.SECURITY, чтобы подключаться к источнику-БА /// </summary> public double Execute(ISecurity sec, int barNum) { double failRes = Constants.NaN; if (m_repeatLastPx) { failRes = Double.IsNaN(m_prevPx) ? Constants.NaN : m_prevPx; } Dictionary <DateTime, double> basePrices; #region Get cache { string cashKey = VariableId + "_basePrices"; basePrices = Context.LoadObject(cashKey) as Dictionary <DateTime, double>; if (basePrices == null) { basePrices = new Dictionary <DateTime, double>(); Context.StoreObject(cashKey, basePrices); } } #endregion Get cache if (sec == null) { return(failRes); } int len = sec.Bars.Count; if (len <= 0) { return(failRes); } double px; DateTime lastBarDate = sec.Bars[barNum].Date; if ((basePrices.TryGetValue(lastBarDate, out px)) && DoubleUtil.IsPositive(px)) { m_prevPx = px; // Раз мы нашли валидную цену в архиве, то можно обновить failRes failRes = px; } // Цену в архиве нашли, теперь надо проверить свежие сведения. { int barsCount = ContextBarsCount; if (barNum < barsCount - 1) { // Если история содержит осмысленное значение, то оно уже содержится в failRes return(failRes); } else { #region Process last bar(s) #region switch(m_pxMode) switch (m_pxMode) { case BasePxMode.FixedPx: px = m_fixedPx; m_prevPx = px; break; case BasePxMode.LastTrade: if (sec.FinInfo.LastPrice.HasValue) { px = sec.FinInfo.LastPrice.Value; m_prevPx = px; } else { px = failRes; } break; case BasePxMode.BidAskMidPoint: { FinInfo info = sec.FinInfo; if (info.Ask.HasValue && info.Bid.HasValue && info.AskSize.HasValue && info.BidSize.HasValue && (info.AskSize.Value > 0) && (info.BidSize.Value > 0)) { px = (info.Ask.Value + info.Bid.Value) / 2; m_prevPx = px; } else if (info.Ask.HasValue && info.AskSize.HasValue && (info.AskSize.Value > 0)) { px = info.Ask.Value; m_prevPx = px; } else if (info.Bid.HasValue && info.BidSize.HasValue && (info.BidSize.Value > 0)) { px = info.Bid.Value; m_prevPx = px; } else { // Приемлемо ли такое решение? if (info.LastPrice.HasValue) { px = info.LastPrice.Value; m_prevPx = px; } else { px = failRes; } } } break; default: throw new NotImplementedException("pxMode:" + m_pxMode); } #endregion switch(m_pxMode) basePrices[lastBarDate] = px; double displayValue = FixedValue.ConvertToDisplayUnits(m_valueMode, px); m_displayPrice.Value = displayValue; return(px); #endregion Process last bar(s) } } }
public SecurityTSlab(ISecurity security) { finInfo = security.FinInfo; InitializeSecurity(security); }
/// <summary> /// Обработчик под тип входных данных OPTION_SERIES /// </summary> public InteractiveSeries Execute(IOptionSeries optSer, IList <double> rates) { InteractiveSeries res = m_context.LoadObject(VariableId + "theorSmile") as InteractiveSeries; if (res == null) { res = new InteractiveSeries(); // Здесь так надо -- мы делаем новую улыбку m_context.StoreObject(VariableId + "theorSmile", res); } if (optSer == null) { return(res); } int len = optSer.UnderlyingAsset.Bars.Count; if (len <= 0) { return(res); } FinInfo bSecFinInfo = optSer.UnderlyingAsset.FinInfo; if (!bSecFinInfo.LastPrice.HasValue) { return(res); } if (rates.Count <= 0) { //throw new ScriptException("There should be some values in second argument 'rates'."); return(res); } //IDataBar bar = optSer.UnderlyingAsset.Bars[len - 1]; double futPx = bSecFinInfo.LastPrice.Value; // ФОРТС использует плоское календарное время DateTime optExpiry = optSer.ExpirationDate.Date.Add(m_expiryTime); double dT = (optExpiry - bSecFinInfo.LastUpdate).TotalYears(); double ratePct = rates[rates.Count - 1]; 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(res); } 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); m_context.Log(msg, MessageType.Error, true); return(res); } if (Double.IsNaN(ratePct)) { //throw new ScriptException("Argument 'rate' contains NaN for some strange reason. rate:" + rate); return(res); } // TODO: переписаться на обновление старых значений //res.ControlPoints.Clear(); List <InteractiveObject> controlPoints = new List <InteractiveObject>(); List <double> xs = new List <double>(); List <double> ys = new List <double>(); IOptionStrikePair[] pairs = (from pair in optSer.GetStrikePairs() //orderby pair.Strike ascending -- уже отсортировано! select pair).ToArray(); for (int j = 0; j < pairs.Length; j++) { bool showPoint = true; IOptionStrikePair sInfo = pairs[j]; double k = sInfo.Strike; //// Сверхдалекие страйки игнорируем //if ((sInfo.Strike < m_minStrike) || (m_maxStrike < sInfo.Strike)) //{ // showPoint = false; //} if ((sInfo.PutFinInfo == null) || (sInfo.CallFinInfo == null) || (!sInfo.PutFinInfo.TheoreticalPrice.HasValue) || (!sInfo.PutFinInfo.Volatility.HasValue) || (sInfo.PutFinInfo.TheoreticalPrice.Value <= 0) || (sInfo.PutFinInfo.Volatility.Value <= 0) || (!sInfo.CallFinInfo.TheoreticalPrice.HasValue) || (!sInfo.CallFinInfo.Volatility.HasValue) || (sInfo.CallFinInfo.TheoreticalPrice.Value <= 0) || (sInfo.CallFinInfo.Volatility.Value <= 0)) { continue; } double prec; // Биржа шлет несогласованную улыбку //double virtualExchangeF = sInfo.CallFinInfo.TheoreticalPrice.Value - sInfo.PutFinInfo.TheoreticalPrice.Value + sInfo.Strike; if ((m_optionType == StrikeType.Any) || (m_optionType == StrikeType.Put)) { double optSigma = sInfo.PutFinInfo.Volatility.Value; if ((!DoubleUtil.IsOne(m_multPx)) || (!DoubleUtil.IsZero(m_shiftPx))) { double optPx = sInfo.PutFinInfo.TheoreticalPrice.Value * m_multPx + m_shiftPx * sInfo.Tick; if ((optPx <= 0) || (Double.IsNaN(optPx))) { optSigma = 0; } else { optSigma = FinMath.GetOptionSigma(futPx, k, dT, optPx, ratePct, false, out prec); } } double vol = optSigma; // ReSharper disable once UseObjectOrCollectionInitializer InteractivePointActive ip = new InteractivePointActive(k, vol); ip.Geometry = Geometries.Ellipse; ip.Color = AlphaColors.Cyan; ip.Tooltip = String.Format("K:{0}; IV:{1:0.00}", k, Constants.PctMult * optSigma); if (showPoint && (vol > 0)) { controlPoints.Add(new InteractiveObject(ip)); } if ((xs.Count <= 0) || (!DoubleUtil.AreClose(k, xs[xs.Count - 1]))) { xs.Add(k); ys.Add(vol); } } if ((m_optionType == StrikeType.Any) || (m_optionType == StrikeType.Call)) { double optSigma = sInfo.CallFinInfo.Volatility.Value; if ((!DoubleUtil.IsOne(m_multPx)) || (!DoubleUtil.IsZero(m_shiftPx))) { double optPx = sInfo.CallFinInfo.TheoreticalPrice.Value * m_multPx + m_shiftPx * sInfo.Tick; if ((optPx <= 0) || (Double.IsNaN(optPx))) { optSigma = 0; } else { optSigma = FinMath.GetOptionSigma(futPx, k, dT, optPx, ratePct, true, out prec); } } double vol = optSigma; // ReSharper disable once UseObjectOrCollectionInitializer InteractivePointActive ip = new InteractivePointActive(k, vol); ip.Geometry = Geometries.Ellipse; ip.Color = AlphaColors.DarkCyan; ip.Tooltip = String.Format("K:{0}; IV:{1:0.00}", k, Constants.PctMult * optSigma); if (showPoint && (vol > 0)) { controlPoints.Add(new InteractiveObject(ip)); } if ((xs.Count <= 0) || (!DoubleUtil.AreClose(k, xs[xs.Count - 1]))) { xs.Add(k); ys.Add(vol); } } } res.ControlPoints = new ReadOnlyCollection <InteractiveObject>(controlPoints); 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; try { if (xs.Count >= BaseCubicSpline.MinNumberOfNodes) { NotAKnotCubicSpline spline = new NotAKnotCubicSpline(xs, ys); info.ContinuousFunction = spline; info.ContinuousFunctionD1 = spline.DeriveD1(); res.Tag = info; } } catch (Exception ex) { m_context.Log(ex.ToString(), MessageType.Error, true); return(Constants.EmptySeries); } return(res); }
/// <summary> /// Обработчик под тип входных данных OPTION_SERIES /// </summary> public InteractiveSeries Execute(double price, double trueTimeToExpiry, IOptionSeries optSer, double ratePct, int barNum) { int barsCount = ContextBarsCount; if ((barNum < barsCount - 1) || (optSer == null)) { return(Constants.EmptySeries); } // PROD-5952 - Не надо дергать стакан без нужды //optSer.UnderlyingAsset.UpdateQueueData(); FinInfo bSecFinInfo = optSer.UnderlyingAsset.FinInfo; if (bSecFinInfo.LastPrice == null) { return(Constants.EmptySeries); } double futPx = price; // ФОРТС использует плоское календарное время DateTime optExpiry = optSer.ExpirationDate.Date.Add(m_expiryTime); double dT = (optExpiry - bSecFinInfo.LastUpdate).TotalYears(); 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(futPx) || (futPx < Double.Epsilon)) { // [{0}] Base asset price must be positive value. F:{1} string msg = RM.GetStringFormat("OptHandlerMsg.FutPxMustBePositive", GetType().Name, futPx); m_context.Log(msg, MessageType.Error, true); return(Constants.EmptySeries); } if (Double.IsNaN(trueTimeToExpiry) || (trueTimeToExpiry < Double.Epsilon)) { string msg = String.Format("[{0}] trueTimeToExpiry must be positive value. dT:{1}", GetType().Name, trueTimeToExpiry); 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 effectiveTime = m_rescaleTime ? trueTimeToExpiry : dT; List <double> xs = new List <double>(); List <double> ys = new List <double>(); IOptionStrikePair[] pairs = (from pair in optSer.GetStrikePairs() //orderby pair.Strike ascending -- уже отсортировано! select pair).ToArray(); if (pairs.Length < 2) { string msg = String.Format("[{0}] optSer must contain few strike pairs. pairs.Length:{1}", GetType().Name, pairs.Length); m_context.Log(msg, MessageType.Warning, true); return(Constants.EmptySeries); } for (int j = 0; j < pairs.Length; j++) { //bool showPoint = true; IOptionStrikePair sInfo = pairs[j]; double k = sInfo.Strike; //// Сверхдалекие страйки игнорируем //if ((k < m_minStrike) || (m_maxStrike < k)) //{ // showPoint = false; //} if ((sInfo.PutFinInfo == null) || (sInfo.CallFinInfo == null) || (!sInfo.PutFinInfo.TheoreticalPrice.HasValue) || (!sInfo.PutFinInfo.Volatility.HasValue) || (sInfo.PutFinInfo.TheoreticalPrice.Value <= 0) || (sInfo.PutFinInfo.Volatility.Value <= 0) || (!sInfo.CallFinInfo.TheoreticalPrice.HasValue) || (!sInfo.CallFinInfo.Volatility.HasValue) || (sInfo.CallFinInfo.TheoreticalPrice.Value <= 0) || (sInfo.CallFinInfo.Volatility.Value <= 0)) { continue; } // Биржа шлет несогласованную улыбку //double virtualExchangeF = sInfo.CallFinInfo.TheoreticalPrice.Value - sInfo.PutFinInfo.TheoreticalPrice.Value + sInfo.Strike; if ((m_optionType == StrikeType.Any) || (m_optionType == StrikeType.Put)) { double optSigma = sInfo.PutFinInfo.Volatility.Value; if (m_rescaleTime) { // optSigma = FinMath.GetOptionSigma(futPx, k, effectiveTime, optPx, 0, false); optSigma = FinMath.RescaleIvToAnotherTime(dT, optSigma, trueTimeToExpiry); } double optPx = sInfo.PutFinInfo.TheoreticalPrice ?? Double.NaN; //// ReSharper disable once UseObjectOrCollectionInitializer //InteractivePointActive ip = new InteractivePointActive(k, optSigma); //ip.IsActive = m_showNodes; //ip.Geometry = Geometries.Ellipse; //ip.Color = System.Windows.Media.Colors.Cyan; //ip.Tooltip = String.Format("K:{0}; IV:{1:0.00}; Px:{2}\r\ndT:{3:0.000}; Date:{4}", // k, Constants.PctMult * optSigma, optPx, // FixedValue.ConvertToDisplayUnits(FixedValueMode.YearsAsDays, effectiveTime), // bSecFinInfo.LastUpdate.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture)); if (optSigma > 0) { // Это условие позволяет не вставлять точки с совпадающими абсциссами if ((xs.Count <= 0) || (!DoubleUtil.AreClose(k, xs[xs.Count - 1]))) { xs.Add(k); ys.Add(optSigma); } } } if ((m_optionType == StrikeType.Any) || (m_optionType == StrikeType.Call)) { double optSigma = sInfo.CallFinInfo.Volatility.Value; if (m_rescaleTime) { // optSigma = FinMath.GetOptionSigma(futPx, k, effectiveTime, optPx, 0, false); optSigma = FinMath.RescaleIvToAnotherTime(dT, optSigma, trueTimeToExpiry); } double optPx = sInfo.CallFinInfo.TheoreticalPrice ?? Double.NaN; //// ReSharper disable once UseObjectOrCollectionInitializer //InteractivePointActive ip = new InteractivePointActive(k, optSigma); //ip.IsActive = m_showNodes; //ip.Geometry = Geometries.Ellipse; //ip.Color = System.Windows.Media.Colors.Cyan; //ip.Tooltip = String.Format("K:{0}; IV:{1:0.00}; Px:{2}\r\ndT:{3:0.000}; Date:{4}", // k, Constants.PctMult * optSigma, optPx, // FixedValue.ConvertToDisplayUnits(FixedValueMode.YearsAsDays, effectiveTime), // bSecFinInfo.LastUpdate.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture)); if (optSigma > 0) { // Это условие позволяет не вставлять точки с совпадающими абсциссами if ((xs.Count <= 0) || (!DoubleUtil.AreClose(k, xs[xs.Count - 1]))) { xs.Add(k); ys.Add(optSigma); } } } } #region 3. Строим сплайн по биржевой улыбке с узлами в страйках NotAKnotCubicSpline spline = null, splineD1 = null; try { if (xs.Count >= BaseCubicSpline.MinNumberOfNodes) { spline = new NotAKnotCubicSpline(xs, ys); splineD1 = spline.DeriveD1(); } else { return(Constants.EmptySeries); } } catch (Exception ex) { string msg = String.Format("bSecFinInfo.LastUpdate:{0}; Bars.Last.Date:{1}\r\n\r\nException:{2}", bSecFinInfo.LastUpdate, optSer.UnderlyingAsset.Bars[optSer.UnderlyingAsset.Bars.Count - 1].Date, ex); m_context.Log(msg, MessageType.Error, true); return(Constants.EmptySeries); } #endregion 3. Строим сплайн по биржевой улыбке с узлами в страйках #region 5. С помощью сплайна уже можно строить гладкую улыбку double futStep = optSer.UnderlyingAsset.Tick; double dK = pairs[1].Strike - pairs[0].Strike; SortedDictionary <double, IOptionStrikePair> strikePrices; if (!SmileImitation5.TryPrepareImportantPoints(pairs, futPx, futStep, -1, out strikePrices)) { string msg = String.Format("[WARNING:{0}] It looks like there is no suitable points for the smile. pairs.Length:{1}", GetType().Name, pairs.Length); m_context.Log(msg, MessageType.Warning, true); return(Constants.EmptySeries); } List <InteractiveObject> controlPoints = new List <InteractiveObject>(); //for (int j = 0; j < pairs.Length; j++) foreach (var kvp in strikePrices) { bool showPoint = (kvp.Value != null); double k = kvp.Key; double sigma; if (!spline.TryGetValue(k, out sigma)) { continue; } double vol = sigma; if (Double.IsNaN(sigma) || Double.IsInfinity(sigma) || (sigma < Double.Epsilon)) { continue; } InteractivePointLight ip; if (m_showNodes && showPoint) { // Как правило, эта ветка вообще не используется, // потому что я не смотрю узлы биржевой улыбки. double optPx = Double.NaN; // ReSharper disable once UseObjectOrCollectionInitializer InteractivePointActive tip = new InteractivePointActive(k, vol); tip.IsActive = m_showNodes && showPoint; tip.Geometry = Geometries.Ellipse; tip.Color = AlphaColors.Cyan; tip.Tooltip = String.Format("K:{0}; IV:{1:P2}; Px:{2}\r\ndT:{3:0.000}; Date:{4}", k, vol, optPx, FixedValue.ConvertToDisplayUnits(FixedValueMode.YearsAsDays, effectiveTime), bSecFinInfo.LastUpdate.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture)); ip = tip; } else { ip = new InteractivePointLight(k, vol); } InteractiveObject obj = new InteractiveObject(ip); controlPoints.Add(obj); } #endregion 5. С помощью сплайна уже можно строить гладкую улыбку // ReSharper disable once UseObjectOrCollectionInitializer InteractiveSeries res = new InteractiveSeries(); // Здесь так надо -- мы делаем новую улыбку res.ControlPoints = new ReadOnlyCollection <InteractiveObject>(controlPoints); 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 = effectiveTime; info.Expiry = optSer.ExpirationDate; info.ScriptTime = scriptTime; info.RiskFreeRate = ratePct; info.BaseTicker = baseSec.Symbol; info.ContinuousFunction = spline; info.ContinuousFunctionD1 = splineD1; res.Tag = info; return(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 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); }