/// <summary> /// Записываем в локальный кеш признак и дату того, /// что данный блок уже работал правильно (например, был полностью готов к торговле) /// </summary> /// <param name="now">время выставления состояния</param> /// <param name="state">состояние</param> protected virtual void SetHandlerInitialized(DateTime now, bool state = true) { string key = "Initialized_" + m_variableId; var tuple = Tuple.Create(now, state); var container = new NotClearableContainer <Tuple <DateTime, bool> >(tuple); // Специально без записи на диск, чтобы после перезапуска ТСЛаб объект был пуст m_context.StoreObject(key, container, false); }
/// <summary> /// Загрузить из кеша (локального ИЛИ глобального) серию чисел во времени /// </summary> /// <param name="context">контекст кубика</param> /// <param name="useGlobalCache">флаг глобальный или локальный кеш</param> /// <param name="cashKey">ключ кеша</param> /// <returns>серия из кеша, либо новый объект (который уже помещен в этот кеш)</returns> public static Dictionary <DateTime, double> LoadOrCreateHistoryDict(IContext context, bool useGlobalCache, string cashKey) { Dictionary <DateTime, double> history; if (useGlobalCache) { object globalObj = context.LoadGlobalObject(cashKey, true); history = globalObj as Dictionary <DateTime, double>; // PROD-3970 - 'Важный' объект if (history == null) { var container = globalObj as NotClearableContainer; if ((container != null) && (container.Content != null)) { history = container.Content as Dictionary <DateTime, double>; } } if (history == null) { history = new Dictionary <DateTime, double>(); var container = new NotClearableContainer(history); context.StoreGlobalObject(cashKey, container, true); } } else { object locObj = context.LoadObject(cashKey); history = locObj as Dictionary <DateTime, double>; // PROD-3970 - 'Важный' объект if (history == null) { var container = locObj as NotClearableContainer; if ((container != null) && (container.Content != null)) { history = container.Content as Dictionary <DateTime, double>; } } if (history == null) { history = new Dictionary <DateTime, double>(); var container = new NotClearableContainer(history); context.StoreObject(cashKey, container); } } return(history); }
protected virtual void SaveHistory(Dictionary <DateTime, T> history, string cashKey, bool useGlobalCacheForHistory, bool isStorage = false) { lock (history) { var data = new NotClearableContainer <Dictionary <DateTime, T> >(history); if (useGlobalCacheForHistory) { m_context.StoreGlobalObject(cashKey, data, isStorage); } else { m_context.StoreObject(cashKey, data, isStorage); } m_privateCache = null; } }
/// <summary> /// Обновление исторической серии, которая потенциально может быть сохранена в глобальный кеш. /// При записи в кеш серия помещается в NotClearableContainer, чтобы выживать при очистке памяти. /// </summary> /// <returns> /// true, если новое значение было фактически помещено в серию; /// false возникает, если запись в глобальный кеш блокирована флагом allowGlobalWrite /// </returns> public static bool TryWrite(IContext context, bool useGlobal, bool allowGlobalWrite, int savePeriod, string cashKey, Dictionary <DateTime, double> series, DateTime now, double val) { if (useGlobal) { if (allowGlobalWrite) { series[now] = val; if (series.Count % savePeriod == 0) { var container = new NotClearableContainer(series); context.StoreGlobalObject(cashKey, container, true); } return(true); } } else { series[now] = val; return(true); } return(false); }
/// <summary> /// Извлечь из локального кеша историю значений данного индикатора. /// Если ее нет, создать и сразу поместить туда. /// </summary> /// <returns>история значений данного индикатора</returns> private List <double> PreparePositionQtys() { // [2019-01-30] Перевожу на использование NotClearableContainer (PROD-6683) List <double> positionQtys; string key = VariableId + "_positionQtys"; var container = m_context.LoadObject(key) as NotClearableContainer <List <double> >; if (container != null) { positionQtys = container.Content; } else { positionQtys = m_context.LoadObject(key) as List <double>; // Старая ветка на всякий случай } if (positionQtys == null) { positionQtys = new List <double>(); container = new NotClearableContainer <List <double> >(positionQtys); m_context.StoreObject(key, container); } return(positionQtys); }
public IList <double> Execute(ISecurity sec) { //Context.Log(String.Format("[Heartbeat.Execute ( ID:{0} )] I'm checking timer settings.", m_id), MessageType.Warning, false); // PROD-5496 - В режиме оптимизации отключаюсь if (Context.IsOptimization) { return(Constants.EmptyListDouble); } CallState timerState = null; string cashKey = VariableId + "_timerState"; { object localObj = Context.LoadObject(cashKey, false); timerState = localObj as CallState; // PROD-3970 - 'Важный' объект if (timerState == null) { var container = localObj as NotClearableContainer; if ((container != null) && (container.Content != null)) { timerState = container.Content as CallState; } } } //m_timer = Context.LoadObject(VariableId + "m_timer") as IThreadingTimerProfiler; if (timerState == null) { string msg = String.Format("[Heartbeat.Execute ( ID:{0} )] Preparing new timer for agent '{1}'...", m_id, Context.Runtime.TradeName); Context.Log(msg, MessageType.Info, false); var secInfo = new PositionsManager.SecInfo(sec.SecurityDescription); timerState = new CallState(m_id, Context, secInfo, m_onlyAtTradingSession); var timer = new ThreadingTimerProfiler(Recalculate, timerState, m_delayMs, Timeout.Infinite); // Обязательно дозаполняем ссылку на таймер timerState.Timer = timer; var container = new NotClearableContainer(timerState); Context.StoreObject(cashKey, container, false); } else if (timerState.Timer == null) { // PROD-5427 - Добавляю счетчик этого аварийного события и логгирую int problemCounter = 0; if (s_problemCounters.ContainsKey(Context.Runtime.TradeName)) { problemCounter = s_problemCounters[Context.Runtime.TradeName]; } s_problemCounters[Context.Runtime.TradeName] = Interlocked.Increment(ref problemCounter); string msg = String.Format("[Heartbeat.Execute ( ID:{0} )] Timer is null in agent '{1}'. Problem counter: {2}", m_id, Context.Runtime.TradeName, problemCounter); Context.Log(msg, MessageType.Warning, false); if (problemCounter > 3) { // Если проблема систематически повторяется -- выбрасываю ассерт для дальнейшего анализа ситуации Contract.Assert(timerState.Timer != null, msg); } } else { //Contract.Assert(timerState.Timer != null, "Почему вдруг (timerState.Timer==null) ??"); // Если при изменении скрипта пересоздается агент, то контекст становится невалидным? if (Object.ReferenceEquals(Context, timerState.CallContext)) { // Если контекст совпадает, то обновляем режим работы... timerState.OnlyAtTradingSession = m_onlyAtTradingSession; // и перезапускаем таймер try { timerState.Timer.Change(m_delayMs, Timeout.Infinite); // PROD-5427 - При штатной работе блока обнуляю счетчик проблем s_problemCounters[Context.Runtime.TradeName] = 0; } catch (ObjectDisposedException) { // Если таймер уже убит, то надо создать новый timerState.Timer = null; timerState = null; string msg = String.Format("[Heartbeat.Execute ( ID:{0} )] Replacing DISPOSED timer for agent '{1}'...", m_id, Context.Runtime.TradeName); Context.Log(msg, MessageType.Warning, false); // Создаём новый таймер. При этом используем НОВЫЙ m_id var secInfo = new PositionsManager.SecInfo(sec.SecurityDescription); timerState = new CallState(m_id, Context, secInfo, m_onlyAtTradingSession); var timer = new ThreadingTimerProfiler(Recalculate, timerState, m_delayMs, Timeout.Infinite); // Обязательно дозаполняем ссылку на таймер timerState.Timer = timer; var container = new NotClearableContainer(timerState); Context.StoreObject(cashKey, container, false); } } else { // Если по какой-то причине изменился контекст, то создаём новый таймер... timerState.Timer.Dispose(); timerState.Timer = null; timerState = null; string msg = String.Format("[Heartbeat.Execute ( ID:{0} )] Replacing timer for agent '{1}'...", m_id, Context.Runtime.TradeName); Context.Log(msg, MessageType.Warning, false); // Создаём новый таймер. При этом используем НОВЫЙ m_id var secInfo = new PositionsManager.SecInfo(sec.SecurityDescription); timerState = new CallState(m_id, Context, secInfo, m_onlyAtTradingSession); var timer = new ThreadingTimerProfiler(Recalculate, timerState, m_delayMs, Timeout.Infinite); // Обязательно дозаполняем ссылку на таймер timerState.Timer = timer; var container = new NotClearableContainer(timerState); Context.StoreObject(cashKey, container, false); } } int len = Context.BarsCount; double[] res = Context.GetArray <double>(len); if (len > 0) { res[len - 1] = m_id; } return(res); }
/// <summary> /// Метод под флаг TemplateTypes.SECURITY, чтобы подключаться к источнику-БА /// </summary> public IList <double> Execute(ISecurity sec) { if (sec == null) { return(Constants.EmptyListDouble); } Dictionary <DateTime, double> hvSigmas; #region Get cache int barLengthInSeconds = (int)sec.IntervalInstance.ToSeconds(); string cashKey = GetGlobalCashKey(sec.Symbol, false, m_useAllData, barLengthInSeconds, m_annualizingMultiplier, m_period); if (UseGlobalCache) { object globalObj = Context.LoadGlobalObject(cashKey, true); hvSigmas = globalObj as Dictionary <DateTime, double>; // PROD-3970 - 'Важный' объект if (hvSigmas == null) { var container = globalObj as NotClearableContainer; if ((container != null) && (container.Content != null)) { hvSigmas = container.Content as Dictionary <DateTime, double>; } } if (hvSigmas == null) { hvSigmas = new Dictionary <DateTime, double>(); var container = new NotClearableContainer(hvSigmas); Context.StoreGlobalObject(cashKey, container, true); } } else { object locObj = Context.LoadObject(cashKey); hvSigmas = locObj as Dictionary <DateTime, double>; // PROD-3970 - 'Важный' объект if (hvSigmas == null) { var container = locObj as NotClearableContainer; if ((container != null) && (container.Content != null)) { hvSigmas = container.Content as Dictionary <DateTime, double>; } } if (hvSigmas == null) { hvSigmas = new Dictionary <DateTime, double>(); var container = new NotClearableContainer(hvSigmas); Context.StoreObject(cashKey, container); } } #endregion Get cache List <double> historySigmas = LocalHistory; if (m_reset || m_context.Runtime.IsFixedBarsCount) { historySigmas.Clear(); } int len = Context.BarsCount; // Локальный ключ можно всегда формировать вместе с периодом! string logsLocObjKey = VariableId + "_logs_" + m_period; object logsLocObj = m_context.LoadObject(logsLocObjKey); LinkedList <KeyValuePair <DateTime, double> > logs = logsLocObj as LinkedList <KeyValuePair <DateTime, double> >; #region Get cache // PROD-3970 - 'Важный' объект if (logs == null) { var container = logsLocObj as NotClearableContainer; if ((container != null) && (container.Content != null)) { logs = container.Content as LinkedList <KeyValuePair <DateTime, double> >; } } if (logs == null) { logs = new LinkedList <KeyValuePair <DateTime, double> >(); var container = new NotClearableContainer(logs); m_context.StoreObject(logsLocObjKey, container); } #endregion Get cache if (m_reset || m_context.Runtime.IsFixedBarsCount) { logs.Clear(); } if (len <= 0) { return(historySigmas); } // Типа, кеширование? for (int j = historySigmas.Count; j < len; j++) { IDataBar bar; try { // Наблюдал на реале странную картину (ВО ВРЕМЯ КЛИРИНГА!): // Context.BarsCount == 3843 && sec.Bars.Count == 3842 bar = sec.Bars[j]; // если бар технический (то есть имеет нулевой объём), пропускаем его // 2017-04-26 - На эксанте при запросе истории все бары имеют нулевой объём, но при этом большинство из них являются нормальными: // имеют ненулевой размах и осмысленные значения открытия/закрытия if ((bar.Volume <= Double.Epsilon) && (DoubleUtil.AreClose(bar.High, bar.Low))) { // пишу NaN в такой ситуации historySigmas.Add(Constants.NaN); continue; } } catch (ArgumentOutOfRangeException) { // Перехватываю aorEx и пишу NaN в такой ситуации historySigmas.Add(Constants.NaN); continue; } DateTime t = bar.Date; double v = bar.Close; double ln = Math.Log(v); Contract.Assert(logs != null, "Каким образом переменная logs оказалась null?"); logs.AddLast(new KeyValuePair <DateTime, double>(t, ln)); double hv; if (TryEstimateHv( logs, m_period, barLengthInSeconds, m_annualizingMultiplier, m_useAllData, out hv)) { double vol = hv; historySigmas.Add(vol); lock (hvSigmas) { hvSigmas[t] = vol; } } else { historySigmas.Add(Constants.NaN); } } // Попытку записи в глобальный кеш делаю только в самом конце всех вычислений // для экономии времени на сериализацию и запись lock (hvSigmas) { if (sec.Bars.Count > len - 1) { // Наблюдал на реале странную картину (ВО ВРЕМЯ КЛИРИНГА!): // Context.BarsCount == 3760 && sec.Bars.Count == 3759 bool success = IvOnF.TryWrite(m_context, UseGlobalCache, AllowGlobalReadWrite, GlobalSavePeriod, cashKey, hvSigmas, sec.Bars[len - 1].Date, historySigmas[historySigmas.Count - 1]); } return(new ReadOnlyCollection <double>(historySigmas)); } }
/// <summary> /// Метод под флаг TemplateTypes.SECURITY, чтобы подключаться к источнику-БА /// </summary> public IList <double> Execute(ISecurity sec) { if (sec == null) { return(Constants.EmptyListDouble); } Dictionary <DateTime, double> hvSigmas; #region Get cache int barLengthInSeconds = (int)sec.IntervalInstance.ToSeconds(); string cashKey = GetGlobalCashKey(sec.Symbol, false, m_useAllData, barLengthInSeconds, m_annualizingMultiplier); if (UseGlobalCache) { object globalObj = Context.LoadGlobalObject(cashKey, true); hvSigmas = globalObj as Dictionary <DateTime, double>; // 'Важный' объект if (hvSigmas == null) { var container = globalObj as NotClearableContainer; if ((container != null) && (container.Content != null)) { hvSigmas = container.Content as Dictionary <DateTime, double>; } } if (hvSigmas == null) { hvSigmas = new Dictionary <DateTime, double>(); var container = new NotClearableContainer(hvSigmas); Context.StoreGlobalObject(cashKey, container, true); } } else { object locObj = Context.LoadObject(cashKey); hvSigmas = locObj as Dictionary <DateTime, double>; // 'Важный' объект if (hvSigmas == null) { var container = locObj as NotClearableContainer; if ((container != null) && (container.Content != null)) { hvSigmas = container.Content as Dictionary <DateTime, double>; } } if (hvSigmas == null) { hvSigmas = new Dictionary <DateTime, double>(); var container = new NotClearableContainer(hvSigmas); Context.StoreObject(cashKey, container); } } #endregion Get cache List <double> historySigmas = LocalHistory; if (m_reset || m_context.Runtime.IsFixedBarsCount) { historySigmas.Clear(); } int len = Context.BarsCount; object logsLocObj = m_context.LoadObject(VariableId + "logs"); LinkedList <KeyValuePair <DateTime, double> > logs = logsLocObj as LinkedList <KeyValuePair <DateTime, double> >; #region Get cache // 'Важный' объект if (logs == null) { var container = logsLocObj as NotClearableContainer; if ((container != null) && (container.Content != null)) { logs = container.Content as LinkedList <KeyValuePair <DateTime, double> >; } } if (logs == null) { logs = new LinkedList <KeyValuePair <DateTime, double> >(); var container = new NotClearableContainer(logs); m_context.StoreObject(VariableId + "logs", container); } #endregion Get cache if (m_reset || m_context.Runtime.IsFixedBarsCount) { logs.Clear(); } if (len <= 0) { return(historySigmas); } // Кеширование for (int j = historySigmas.Count; j < len; j++) { IDataBar bar; try { bar = sec.Bars[j]; // если бар технический (то есть имеет нулевой объём), пропускаем его if ((bar.Volume <= Double.Epsilon) && (DoubleUtil.AreClose(bar.High, bar.Low))) { // пишу NaN в такой ситуации historySigmas.Add(Constants.NaN); continue; } } catch (ArgumentOutOfRangeException) { // Перехватываю aorEx и пишу NaN в такой ситуации historySigmas.Add(Constants.NaN); continue; } DateTime t = bar.Date; double v = bar.Close; double ln = Math.Log(v); logs.AddLast(new KeyValuePair <DateTime, double>(t, ln)); double hv; if (TryEstimateHv( logs, m_period, barLengthInSeconds, m_annualizingMultiplier, m_useAllData, out hv)) { double vol = hv; historySigmas.Add(vol); lock (hvSigmas) { hvSigmas[t] = vol; } } else { historySigmas.Add(Constants.NaN); } } // Попытку записи в глобальный кеш делаю только в самом конце всех вычислений // для экономии времени на сериализацию и запись lock (hvSigmas) { if (sec.Bars.Count > len - 1) { bool success = IvOnF.TryWrite(m_context, UseGlobalCache, AllowGlobalReadWrite, GlobalSavePeriod, cashKey, hvSigmas, sec.Bars[len - 1].Date, historySigmas[historySigmas.Count - 1]); } return(new ReadOnlyCollection <double>(historySigmas)); } }
public IList <double> Execute(ISecurity sec) { //Context.Log(String.Format("[Heartbeat.Execute ( ID:{0} )] I'm checking timer settings.", m_id), MessageType.Warning, false); // PROD-5496 - В режиме оптимизации отключаюсь if (Context.IsOptimization) { return(Constants.EmptyListDouble); } var secrt = sec as ISecurityRt; if (secrt?.IsPortfolioActive != true) { return(Constants.EmptyListDouble); } TimerInfo timerState; string cashKey = VariableId + "_timerState"; { object localObj = Context.LoadObject(cashKey); timerState = localObj as TimerInfo; // PROD-3970 - 'Важный' объект if (timerState == null) { if (localObj is NotClearableContainer container && container.Content != null) { timerState = container.Content as TimerInfo; } } } if (timerState == null) { string msg = $"[RecalcScheduler({m_id})] Preparing new timer for agent '{Context.Runtime.TradeName}'..."; Context.Log(msg); timerState = TimerInfo.Create(Context, secrt, RecalcTime); var container = new NotClearableContainer(timerState); Context.StoreObject(cashKey, container); } else if (timerState.Timer == null) { // PROD-5427 - Добавляю счетчик этого аварийного события и логгирую int problemCounter = 0; if (s_problemCounters.ContainsKey(Context.Runtime.TradeName)) { problemCounter = s_problemCounters[Context.Runtime.TradeName]; } s_problemCounters[Context.Runtime.TradeName] = Interlocked.Increment(ref problemCounter); string msg = $"[RecalcScheduler({m_id})] Timer is null in agent '{Context.Runtime.TradeName}'. Problem counter: {problemCounter}"; Context.Log(msg, MessageType.Warning); if (problemCounter > 3) { // Если проблема систематически повторяется -- выбрасываю ассерт для дальнейшего анализа ситуации Contract.Assert(timerState.Timer != null, msg); } } else { // Если при изменении скрипта пересоздается агент, то контекст становится невалидным? if (!ReferenceEquals(Context, timerState.CallContext)) { // Если по какой-то причине изменился контекст, то создаём новый таймер... string msg = $"[RecalcScheduler({m_id})] Replacing timer for agent '{Context.Runtime.TradeName}'..."; Context.Log(msg, MessageType.Warning); // Создаём новый таймер. При этом используем НОВЫЙ m_id timerState = TimerInfo.Create(Context, secrt, RecalcTime); var container = new NotClearableContainer(timerState); Context.StoreObject(cashKey, container); } } int len = Context.BarsCount; double[] res = Context.GetArray <double>(len); if (len > 0) { res[len - 1] = m_id; } return(res); }
private double Process(InteractiveSeries profile, double moneyness, int barNum) { // В данном случае намеренно возвращаю Double.NaN double failRes = Double.NaN; if (m_repeatLastValue) { failRes = Double.IsNaN(m_prevValue) ? Double.NaN : m_prevValue; // В данном случае намеренно возвращаю Double.NaN } Dictionary <DateTime, double> results; #region Get cache // [2019-01-30] Перевожу на использование NotClearableContainer (PROD-6683) string key = m_variableId + "_results"; var container = m_context.LoadObject(key) as NotClearableContainer <Dictionary <DateTime, double> >; if (container != null) { results = container.Content; } else { results = m_context.LoadObject(key) as Dictionary <DateTime, double>; // Старая ветка на всякий случай } if (results == null) { string msg = String.Format(RM.GetString("OptHandlerMsg.GetValueAtm.CacheNotFound"), GetType().Name, key.GetHashCode()); m_context.Log(msg, MessageType.Info); results = new Dictionary <DateTime, double>(); container = new NotClearableContainer <Dictionary <DateTime, double> >(results); m_context.StoreObject(key, container); } #endregion Get cache int len = m_context.BarsCount; if (len <= 0) { return(failRes); } // Вот так не работает. По всей видимости, это прямая индексация от утра //DateTime now = m_context.Runtime.GetBarTime(barNum); ISecurity sec = m_context.Runtime.Securities.FirstOrDefault(); if ((sec == null) || (sec.Bars.Count <= barNum)) { return(failRes); } DateTime now = sec.Bars[barNum].Date; if (results.TryGetValue(now, out double rawRes) && (barNum < len - 1)) // !!! ВАЖНО !!! На последнем баре ВСЕГДА заново делаем вычисления { m_prevValue = rawRes; return(rawRes); } else { int barsCount = ContextBarsCount; if (barNum < barsCount - 1) { // Если история содержит осмысленное значение, то оно уже содержится в failRes return(failRes); } else { #region Process last bar(s) if (profile == null) { return(failRes); } SmileInfo profInfo = profile.GetTag <SmileInfo>(); if ((profInfo == null) || (profInfo.ContinuousFunction == null)) { return(failRes); } double f = profInfo.F; double dT = profInfo.dT; if (!DoubleUtil.IsPositive(f)) { string msg = String.Format(RM.GetString("OptHandlerMsg.FutPxMustBePositive"), GetType().Name, f); m_context.Log(msg, MessageType.Error); // [GLSP-1557] В данном случае намеренно возвращаю Double.NaN, чтобы предотвратить распространение // заведомо неправильных данных по системе (их попадание в дельта-хеджер и т.п.). return(Double.NaN); } if (!DoubleUtil.IsPositive(dT)) { string msg = String.Format(RM.GetString("OptHandlerMsg.TimeMustBePositive"), GetType().Name, dT); m_context.Log(msg, MessageType.Error); // [GLSP-1557] В данном случае намеренно возвращаю Double.NaN, чтобы предотвратить распространение // заведомо неправильных данных по системе (их попадание в дельта-хеджер и т.п.). return(Double.NaN); } double effectiveF; if (DoubleUtil.IsZero(moneyness)) { effectiveF = f; } else { effectiveF = f * Math.Exp(moneyness * Math.Sqrt(dT)); } if (profInfo.ContinuousFunction.TryGetValue(effectiveF, out rawRes)) { m_prevValue = rawRes; results[now] = rawRes; } else { if (barNum < len - 1) { // [GLSP-1557] Не последний бар? Тогда использую failRes rawRes = failRes; } else { // [GLSP-1557] В данном случае намеренно возвращаю Double.NaN, чтобы предотвратить распространение // заведомо неправильных данных по системе (их попадание в дельта-хеджер и т.п.). return(Double.NaN); } } #endregion Process last bar(s) m_result.Value = rawRes; //m_context.Log(MsgId + ": " + m_result.Value, MessageType.Info, PrintInLog); return(rawRes); } } }
/// <summary> /// Пытается угадать видимую область и если это получается результат складывает в локальный кеш /// </summary> private Rect PrepareVieportSettings(string seriesExpiry, double futPx, double dT, double sigma) { Rect rect; //string key = VariableId + KeySuffix + "_" + (seriesExpiry ?? "NULL"); string key = GetViewportCacheKey(this, seriesExpiry); var container = Context.LoadObject(key) as NotClearableContainer <Rect>; // Проверка на ApplyVisualSettings нужна, чтобы безусловно поменять видимую область при нажатии на кнопку в UI if ((container != null) /*&& (container.Content != null)*/ && (!ApplyVisualSettings) && DoubleUtil.IsPositive(container.Content.Width) && DoubleUtil.IsPositive(container.Content.Height)) // PROD-3901 { rect = container.Content; } else { // PROD-5747 - Если контенер пуст, давайте сделаем в логе запись об этом? // Тогда будет понятно в какой момент он чистится. if ((container == null) /*|| (container.Content == null)*/ || (!DoubleUtil.IsPositive(futPx)) || (!DoubleUtil.IsPositive(sigma))) { string expStr = seriesExpiry ?? "NULL"; string tradeName = (m_context.Runtime?.TradeName ?? "NULL").Replace(Constants.HtmlDot, "."); string msg = String.Format(CultureInfo.InvariantCulture, "[{0}.PrepareVieportSettings] Empty container. Key:'{1}'; futPx:{2}; dT:{3}; sigma:{4}; expiry:{5}; TradeName:'{6}'", GetType().Name, key, futPx, dT, sigma, expStr, tradeName); m_context.Log(msg, MessageType.Info, false); } else if ((container != null) /*&& (container.Content != null)*/ && ((!DoubleUtil.IsPositive(container.Content.Width)) || (!DoubleUtil.IsPositive(container.Content.Height)))) { string expStr = seriesExpiry ?? "NULL"; string tradeName = (m_context.Runtime?.TradeName ?? "NULL").Replace(Constants.HtmlDot, "."); string msg = String.Format(CultureInfo.InvariantCulture, "[{0}.PrepareVieportSettings] BAD RECT. Key:'{1}'; futPx:{2}; dT:{3}; sigma:{4}; expiry:{5}; TradeName:'{6}'; Width:{7}; Height:{8}", GetType().Name, key, futPx, dT, sigma, expStr, tradeName, container.Content.Width, container.Content.Height); m_context.Log(msg, MessageType.Info, false); } //// При самом первом запуске эмулирую нажатие кнопки Apply, чтобы заставить //// CanvasPane реагировать на мои настройки в Borders2. //ApplyVisualSettings = true; double width = (SigmaMult * sigma * Math.Sqrt(dT)) * futPx; // Общая ширина не менее 10% от futPx? //width = Math.Max(width, futPx * 0.05); double left = Math.Max(0, futPx - width); // Чтобы график был симметричен, ширину тоже подрезаю width = Math.Abs(futPx - left); double height = sigma * (m_verticalMultiplier - 1.0 / m_verticalMultiplier); rect = new Rect(futPx - width, sigma * m_verticalMultiplier, 2 * width, height); // PROD-5747 - Сохранять область в кеш можно только если прямоугольник имеет нормальные размеры if (DoubleUtil.IsPositive(rect.Width) && DoubleUtil.IsPositive(rect.Height)) { // При самом первом запуске эмулирую нажатие кнопки Apply, чтобы заставить // CanvasPane реагировать на мои настройки в Borders2. ApplyVisualSettings = true; container = new NotClearableContainer <Rect>(rect); Context.StoreObject(key, container); } } return(rect); }
/// <summary> /// \~english Get history of previous values /// \~russian История предыдущих значений /// </summary> /// <param name="cashKey">ключ кеша</param> /// <param name="useGlobalCacheForHistory">искать серию исторических данных в Глобальном Кеше?</param> /// <param name="fromStorage">читать с диска</param> /// <returns>коллекция с историей</returns> // ReSharper disable once VirtualMemberNeverOverriden.Global protected virtual Dictionary <DateTime, T> GetHistory(string cashKey, bool useGlobalCacheForHistory, bool fromStorage = false) { if ((m_context == null) || String.IsNullOrWhiteSpace(cashKey)) { return(null); } if (m_privateCache == null) { Dictionary <DateTime, T> history = null; if (useGlobalCacheForHistory) { var obj = m_context.LoadGlobalObject(cashKey, fromStorage); switch (obj) { case Dictionary <DateTime, T> t: history = t; break; case NotClearableContainer <Dictionary <DateTime, T> > t: history = t.Content; break; } if (history == null) { string msg = String.Format("[{0}] GLOBAL history '{1}' not found in global cache for key.GetHashCode: {2}", m_context.Runtime.TradeName ?? "EMPTY", cashKey, cashKey.GetHashCode()); m_context.Log(msg, MessageType.Info, false); history = new Dictionary <DateTime, T>(); var data = new NotClearableContainer <Dictionary <DateTime, T> >(history); m_context.StoreGlobalObject(cashKey, data, fromStorage); } } else { var obj = m_context.LoadObject(cashKey, fromStorage); switch (obj) { case Dictionary <DateTime, T> t: history = t; break; case NotClearableContainer <Dictionary <DateTime, T> > t: history = t.Content; break; } if (history == null) { string msg = String.Format("[{0}] Local history '{1}' not found in local cache for key.GetHashCode: {2}", m_context.Runtime.TradeName ?? "EMPTY", cashKey, cashKey.GetHashCode()); m_context.Log(msg, MessageType.Info, false); history = new Dictionary <DateTime, T>(); var data = new NotClearableContainer <Dictionary <DateTime, T> >(history); m_context.StoreObject(cashKey, data, fromStorage); } } m_privateCache = history; } return(m_privateCache); }
public double Execute(InteractiveSeries profile, int barNum) { // В данном случае намеренно возвращаю Double.NaN double failRes = Double.NaN; if (m_repeatLastValue) { failRes = Double.IsNaN(m_prevValue) ? Double.NaN : m_prevValue; // В данном случае намеренно возвращаю Double.NaN } Dictionary <DateTime, double> results; #region Get cache // [2019-01-30] Перевожу на использование NotClearableContainer (PROD-6683) string key = m_variableId + "_results"; var container = m_context.LoadObject(key) as NotClearableContainer <Dictionary <DateTime, double> >; if (container != null) { results = container.Content; } else { results = m_context.LoadObject(key) as Dictionary <DateTime, double>; // Старая ветка на всякий случай } if (results == null) { string msg = String.Format(RM.GetString("OptHandlerMsg.GetValueAtm.CacheNotFound"), GetType().Name, key.GetHashCode()); m_context.Log(msg, MessageType.Info); results = new Dictionary <DateTime, double>(); container = new NotClearableContainer <Dictionary <DateTime, double> >(results); m_context.StoreObject(key, container); } #endregion Get cache int len = m_context.BarsCount; if (len <= 0) { return(failRes); } // Вот так не работает. По всей видимости, это прямая индексация от утра //DateTime now = m_context.Runtime.GetBarTime(barNum); ISecurity sec = m_context.Runtime.Securities.FirstOrDefault(); if ((sec == null) || (sec.Bars.Count <= barNum)) { return(failRes); } DateTime now = sec.Bars[barNum].Date; double rawRes; if (results.TryGetValue(now, out rawRes)) { m_prevValue = rawRes; return(rawRes); } else { int barsCount = ContextBarsCount; if (barNum < barsCount - 1) { // Если история содержит осмысленное значение, то оно уже содержится в failRes return(failRes); } else { #region Process last bar(s) if (profile == null) { return(failRes); } SmileInfo profInfo = profile.GetTag <SmileInfo>(); if ((profInfo == null) || (profInfo.ContinuousFunction == null)) { return(failRes); } double f = profInfo.F; double dT = profInfo.dT; if (Double.IsNaN(f) || (f < Double.Epsilon)) { string msg = String.Format(RM.GetString("OptHandlerMsg.FutPxMustBePositive"), GetType().Name, f); m_context.Log(msg, MessageType.Error); return(failRes); } if (!DoubleUtil.IsZero(m_moneyness)) { if (Double.IsNaN(dT) || (dT < Double.Epsilon)) { string msg = String.Format(RM.GetString("OptHandlerMsg.TimeMustBePositive"), GetType().Name, dT); m_context.Log(msg, MessageType.Error); return(failRes); } } double effectiveF; if (DoubleUtil.IsZero(m_moneyness)) { effectiveF = f; } else { effectiveF = f * Math.Exp(m_moneyness * Math.Sqrt(profInfo.dT)); } if (profInfo.ContinuousFunction.TryGetValue(effectiveF, out rawRes)) { m_prevValue = rawRes; results[now] = rawRes; } else { rawRes = failRes; } #endregion Process last bar(s) m_result.Value = rawRes; m_context.Log(MsgId + ": " + m_result.Value, MessageType.Info, PrintInLog); return(rawRes); } } }