protected override double EaseInCore(double normalizedTime) { // The math below is complicated because we have a few requirements to get the correct look for bounce: // 1) The bounces should be symetrical // 2) Bounciness should control both the amplitude and the period of the bounces // 3) Bounces should control the number of bounces without including the final half bounce to get you back to 1.0 // // Note: Simply modulating a expo or power curve with a abs(sin(...)) wont work because it violates 1) above. // // Constants double bounces = Math.Max(0.0, (double)Bounces); double bounciness = Bounciness; // Clamp the bounciness so we dont hit a divide by zero if (bounciness < 1.0 || DoubleUtil.IsOne(bounciness)) { // Make it just over one. In practice, this will look like 1.0 but avoid divide by zeros. bounciness = 1.001; } double pow = Math.Pow(bounciness, bounces); double oneMinusBounciness = 1.0 - bounciness; // 'unit' space calculations. // Our bounces grow in the x axis exponentially. we define the first bounce as having a 'unit' width of 1.0 and compute // the total number of 'units' using a geometric series. // We then compute which 'unit' the current time is in. double sumOfUnits = (1.0 - pow) / oneMinusBounciness + pow * 0.5; // geometric series with only half the last sum double unitAtT = normalizedTime * sumOfUnits; // 'bounce' space calculations. // Now that we know which 'unit' the current time is in, we can determine which bounce we're in by solving the geometric equation: // unitAtT = (1 - bounciness^bounce) / (1 - bounciness), for bounce. double bounceAtT = Math.Log(-unitAtT * (1.0 - bounciness) + 1.0, bounciness); double start = Math.Floor(bounceAtT); double end = start + 1.0; // 'time' space calculations. // We then project the start and end of the bounce into 'time' space double startTime = (1.0 - Math.Pow(bounciness, start)) / (oneMinusBounciness * sumOfUnits); double endTime = (1.0 - Math.Pow(bounciness, end)) / (oneMinusBounciness * sumOfUnits); // Curve fitting for bounce. double midTime = (startTime + endTime) * 0.5; double timeRelativeToPeak = normalizedTime - midTime; double radius = midTime - startTime; double amplitude = Math.Pow(1.0 / bounciness, (bounces - start)); // Evaluate a quadratic that hits (startTime,0), (endTime, 0), and peaks at amplitude. return((-amplitude / (radius * radius)) * (timeRelativeToPeak - radius) * (timeRelativeToPeak + radius)); }
/// <summary> /// Converts a DataGridLength instance to a String given the CultureInfo. /// </summary> /// <param name="gl">DataGridLength instance to convert.</param> /// <param name="cultureInfo">The culture to use.</param> /// <returns>String representation of the object.</returns> internal static string ConvertToString(DataGridLength length, CultureInfo cultureInfo) { switch (length.UnitType) { case DataGridLengthUnitType.Auto: case DataGridLengthUnitType.SizeToCells: case DataGridLengthUnitType.SizeToHeader: return(length.UnitType.ToString()); // Star has one special case when value is "1.0" in which the value can be dropped. case DataGridLengthUnitType.Star: return(DoubleUtil.IsOne(length.Value) ? "*" : Convert.ToString(length.Value, cultureInfo) + "*"); // Print out the numeric value. "px" can be omitted. default: return(Convert.ToString(length.Value, cultureInfo)); } }
// Token: 0x0600072A RID: 1834 RVA: 0x00016B3C File Offset: 0x00014D3C internal static string ToString(GridLength gl, CultureInfo cultureInfo) { GridUnitType gridUnitType = gl.GridUnitType; if (gridUnitType == GridUnitType.Auto) { return("Auto"); } if (gridUnitType != GridUnitType.Star) { return(Convert.ToString(gl.Value, cultureInfo)); } if (!DoubleUtil.IsOne(gl.Value)) { return(Convert.ToString(gl.Value, cultureInfo) + "*"); } return("*"); }
//------------------------------------------------------------------- // // Internal Methods // //------------------------------------------------------------------- #region Internal Methods /// <summary> /// Converts a GridLength instance to a String given the CultureInfo. /// </summary> /// <param name="gl">GridLength instance to convert.</param> /// <param name="cultureInfo">Culture Info.</param> /// <returns>String representation of the object.</returns> static internal string ToString(GridLength gl, CultureInfo cultureInfo) { switch (gl.GridUnitType) { // for Auto print out "Auto". value is always "1.0" case (GridUnitType.Auto): return("Auto"); // Star has one special case when value is "1.0". // in this case drop value part and print only "Star" case (GridUnitType.Star): return( DoubleUtil.IsOne(gl.Value) ? "*" : Convert.ToString(gl.Value, cultureInfo) + "*"); // for Pixel print out the numeric value. "px" can be omitted. default: return(Convert.ToString(gl.Value, cultureInfo)); } }
/// <summary> /// Converts a RibbonControlLength instance to a String given the CultureInfo. /// </summary> internal static string ToString(RibbonControlLength length, CultureInfo cultureInfo) { switch (length.RibbonControlLengthUnitType) { // for Auto print out "Auto". value is always "1.0" case RibbonControlLengthUnitType.Auto: return("Auto"); case RibbonControlLengthUnitType.Item: return(Convert.ToString(length.Value, cultureInfo) + "items"); // Star has one special case when value is "1.0". // in this case drop value part and print only "Star" case RibbonControlLengthUnitType.Star: return(DoubleUtil.IsOne(length.Value) ? "*" : Convert.ToString(length.Value, cultureInfo) + "*"); // for Pixel print out the numeric value. "px" can be omitted. default: return(Convert.ToString(length.Value, cultureInfo)); } }
/// <summary> /// /// </summary> /// <param name="H">0---1</param> /// <param name="S">0---1</param> /// <param name="B">0---1</param> /// <returns></returns> public static Color ColorFromHsb(double H, double S, double B) { double red = 0.0, green = 0.0, blue = 0.0; if (DoubleUtil.IsZero(S)) { red = green = blue = B; } else { var h = DoubleUtil.IsOne(H) ? 0d : (H * 6.0); int i = (int)Math.Floor(h); var f = h - i; var r = B * (1.0 - S); var s = B * (1.0 - S * f); var t = B * (1.0 - S * (1.0 - f)); switch (i) { case 0: red = B; green = t; blue = r; break; case 1: red = s; green = B; blue = r; break; case 2: red = r; green = B; blue = t; break; case 3: red = r; green = s; blue = B; break; case 4: red = t; green = r; blue = B; break; case 5: red = B; green = r; blue = s; break; } } return(Color.FromRgb((byte)Math.Round(red * 255.0), (byte)Math.Round(green * 255.0), (byte)Math.Round(blue * 255.0))); }
/// <summary> /// Content arrangement. /// </summary> /// <param name="finalSize">The final size that element should use to arrange itself and its children.</param> protected override sealed Size ArrangeOverride(Size finalSize) { Transform pageTransform; ScaleTransform pageScaleTransform; Visual pageVisual; Size pageSize, pageZoom; CheckDisposed(); if (_pageVisualClone == null) { if (_pageHost == null) { _pageHost = new DocumentPageHost(); this.AddVisualChild(_pageHost); } Invariant.Assert(_pageHost != null); pageVisual = (_documentPage == null) ? null : _documentPage.Visual; if (pageVisual == null) { // Remove existing visiual children. _pageHost.PageVisual = null; // Reset offset and transform on the page host before Arrange _pageHost.CachedOffset = new Point(); _pageHost.RenderTransform = null; // Size for the page host needs to be set to finalSize _pageHost.Arrange(new Rect(_pageHost.CachedOffset, finalSize)); } else { // Add visual representing the page contents. For performance reasons // first check if it is already insered there. if (_pageHost.PageVisual != pageVisual) { // There might be a case where a visual associated with a page was // inserted to a visual tree before. It got removed later, but GC did not // destroy its parent yet. To workaround this case always check for the parent // of page visual and disconnect it, when necessary. DocumentPageHost.DisconnectPageVisual(pageVisual); _pageHost.PageVisual = pageVisual; } // Compute transform to be applied to the page visual. First take into account // mirroring transform, if necessary. Apply also scaling transform. pageSize = _documentPage.Size; pageTransform = Transform.Identity; // DocumentPage.Visual is always LeftToRight, so if the current // FlowDirection is RightToLeft, need to unmirror the child visual. if (FlowDirection == FlowDirection.RightToLeft) { pageTransform = new MatrixTransform(-1.0, 0.0, 0.0, 1.0, pageSize.Width, 0.0); } // Apply zooming if (!DoubleUtil.IsOne(_pageZoom)) { pageScaleTransform = new ScaleTransform(_pageZoom, _pageZoom); if (pageTransform == Transform.Identity) { pageTransform = pageScaleTransform; } else { pageTransform = new MatrixTransform(pageTransform.Value * pageScaleTransform.Value); } pageSize = new Size(pageSize.Width * _pageZoom, pageSize.Height * _pageZoom); } // Apply stretch properties pageZoom = Viewbox.ComputeScaleFactor(finalSize, pageSize, this.Stretch, this.StretchDirection); if (!DoubleUtil.IsOne(pageZoom.Width) || !DoubleUtil.IsOne(pageZoom.Height)) { pageScaleTransform = new ScaleTransform(pageZoom.Width, pageZoom.Height); if (pageTransform == Transform.Identity) { pageTransform = pageScaleTransform; } else { pageTransform = new MatrixTransform(pageTransform.Value * pageScaleTransform.Value); } pageSize = new Size(pageSize.Width * pageZoom.Width, pageSize.Height * pageZoom.Height); } // Set offset and transform on the page host before Arrange _pageHost.CachedOffset = new Point((finalSize.Width - pageSize.Width) / 2, (finalSize.Height - pageSize.Height) / 2); _pageHost.RenderTransform = pageTransform; // Arrange pagehost to original size of the page. _pageHost.Arrange(new Rect(_pageHost.CachedOffset, _documentPage.Size)); } // Fire sync notification if new page was connected. if (_newPageConnected) { OnPageConnected(); } // Transform for the page has been changed, need to notify TextView about the changes. OnTransformChangedAsync(); } else { if (_pageHost.PageVisual != _pageVisualClone) { // Remove existing visiual children. _pageHost.PageVisual = _pageVisualClone; // Size for the page host needs to be set to finalSize // Use previous offset and transform _pageHost.Arrange(new Rect(_pageHost.CachedOffset, finalSize)); } } return(base.ArrangeOverride(finalSize)); }
internal override void FinalizeCreation() { _bitmapInit.EnsureInitializedComplete(); BitmapSourceSafeMILHandle wicTransformer = null; double scaleX, scaleY; WICBitmapTransformOptions options; GetParamsFromTransform(Transform, out scaleX, out scaleY, out options); using (FactoryMaker factoryMaker = new FactoryMaker()) { try { IntPtr wicFactory = factoryMaker.ImagingFactoryPtr; wicTransformer = _source.WicSourceHandle; if (!DoubleUtil.IsOne(scaleX) || !DoubleUtil.IsOne(scaleY)) { uint width = Math.Max(1, (uint)(scaleX * _source.PixelWidth + 0.5)); uint height = Math.Max(1, (uint)(scaleY * _source.PixelHeight + 0.5)); HRESULT.Check(UnsafeNativeMethods.WICImagingFactory.CreateBitmapScaler( wicFactory, out wicTransformer)); lock (_syncObject) { HRESULT.Check(UnsafeNativeMethods.WICBitmapScaler.Initialize( wicTransformer, _source.WicSourceHandle, width, height, WICInterpolationMode.Fant)); } } if (options != WICBitmapTransformOptions.WICBitmapTransformRotate0) { // Rotations are extremely slow if we're pulling from a decoder because we end // up decoding multiple times. Caching the source lets us rotate faster at the cost // of increased memory usage. wicTransformer = CreateCachedBitmap( null, wicTransformer, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default, _source.Palette); // BitmapSource.CreateCachedBitmap already calculates memory pressure for // the new bitmap, so there's no need to do it before setting it to // WicSourceHandle. BitmapSourceSafeMILHandle rotator = null; HRESULT.Check(UnsafeNativeMethods.WICImagingFactory.CreateBitmapFlipRotator( wicFactory, out rotator)); lock (_syncObject) { HRESULT.Check(UnsafeNativeMethods.WICBitmapFlipRotator.Initialize( rotator, wicTransformer, options)); } wicTransformer = rotator; } // If we haven't introduced either a scaler or rotator, add a null rotator // so that our WicSourceHandle isn't the same as our Source's. if (options == WICBitmapTransformOptions.WICBitmapTransformRotate0 && DoubleUtil.IsOne(scaleX) && DoubleUtil.IsOne(scaleY)) { HRESULT.Check(UnsafeNativeMethods.WICImagingFactory.CreateBitmapFlipRotator( wicFactory, out wicTransformer)); lock (_syncObject) { HRESULT.Check(UnsafeNativeMethods.WICBitmapFlipRotator.Initialize( wicTransformer, _source.WicSourceHandle, WICBitmapTransformOptions.WICBitmapTransformRotate0)); } } WicSourceHandle = wicTransformer; _isSourceCached = _source.IsSourceCached; } catch { _bitmapInit.Reset(); throw; } } CreationCompleted = true; UpdateCachedSettings(); }
/// <summary> /// Clears double's computation fuzz around 0 and 1 /// </summary> internal static double AdjustFIndex(double findex) { return(DoubleUtil.IsZero(findex) ? 0 : (DoubleUtil.IsOne(findex) ? 1 : findex)); }
/// <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>Arranges the content to fit a specified view size.</summary> /// <param name="finalSize">The maximum size that the page view should use to arrange itself and its children.</param> /// <returns>The actual size that the page view used to arrange itself and its children.</returns> // Token: 0x06005D78 RID: 23928 RVA: 0x001A4EA8 File Offset: 0x001A30A8 protected sealed override Size ArrangeOverride(Size finalSize) { this.CheckDisposed(); if (this._pageVisualClone == null) { if (this._pageHost == null) { this._pageHost = new DocumentPageHost(); base.AddVisualChild(this._pageHost); } Invariant.Assert(this._pageHost != null); Visual visual = (this._documentPage == null) ? null : this._documentPage.Visual; if (visual == null) { this._pageHost.PageVisual = null; this._pageHost.CachedOffset = default(Point); this._pageHost.RenderTransform = null; this._pageHost.Arrange(new Rect(this._pageHost.CachedOffset, finalSize)); } else { if (this._pageHost.PageVisual != visual) { DocumentPageHost.DisconnectPageVisual(visual); this._pageHost.PageVisual = visual; } Size size = this._documentPage.Size; Transform transform = Transform.Identity; if (base.FlowDirection == FlowDirection.RightToLeft) { transform = new MatrixTransform(-1.0, 0.0, 0.0, 1.0, size.Width, 0.0); } if (!DoubleUtil.IsOne(this._pageZoom)) { ScaleTransform scaleTransform = new ScaleTransform(this._pageZoom, this._pageZoom); if (transform == Transform.Identity) { transform = scaleTransform; } else { transform = new MatrixTransform(transform.Value * scaleTransform.Value); } size = new Size(size.Width * this._pageZoom, size.Height * this._pageZoom); } Size size2 = Viewbox.ComputeScaleFactor(finalSize, size, this.Stretch, this.StretchDirection); if (!DoubleUtil.IsOne(size2.Width) || !DoubleUtil.IsOne(size2.Height)) { ScaleTransform scaleTransform = new ScaleTransform(size2.Width, size2.Height); if (transform == Transform.Identity) { transform = scaleTransform; } else { transform = new MatrixTransform(transform.Value * scaleTransform.Value); } size = new Size(size.Width * size2.Width, size.Height * size2.Height); } this._pageHost.CachedOffset = new Point((finalSize.Width - size.Width) / 2.0, (finalSize.Height - size.Height) / 2.0); this._pageHost.RenderTransform = transform; this._pageHost.Arrange(new Rect(this._pageHost.CachedOffset, this._documentPage.Size)); } if (this._newPageConnected) { this.OnPageConnected(); } this.OnTransformChangedAsync(); } else if (this._pageHost.PageVisual != this._pageVisualClone) { this._pageHost.PageVisual = this._pageVisualClone; this._pageHost.Arrange(new Rect(this._pageHost.CachedOffset, finalSize)); } return(base.ArrangeOverride(finalSize)); }
protected override bool TryCalculate(Dictionary <DateTime, double> history, DateTime now, int barNum, object[] args, out double val) { int col = 0; double price = (double)args[col++]; double rawDelta = (double)args[col++]; //IOptionSeries optSer = (IOptionSeries)args[col++]; double priceStep = (double)args[col++]; DateTime expirationDate = (DateTime)args[col++]; string underlyingSymbol = (string)args[col++]; DateTime lastUpdate = (DateTime)args[col++]; var baseSecDesc = (DataSource.IDataSourceSecurity)args[col++]; bool permissionToWork = (bool)args[col++]; // Здесь работаем не с парами, а со списком, чтобы потом было легче обобщить на весь опцион целиком. var strikes = (IEnumerable <IOptionStrike>)args[col++]; // Шаг лотности БАЗОВОГО АКТИВА (нужен для Дерибит в первую очередь) double lotTick = (double)args[col++]; val = rawDelta; #region Validate args double futPx = price; // Входные параметры не проинициализированы if (Double.IsNaN(rawDelta) || (!DoubleUtil.IsPositive(futPx))) { return(true); } // Входные параметры не проинициализированы //if ((optSer == null) || (optSer.UnderlyingAsset == null) || (optSer.UnderlyingAsset.SecurityDescription == null)) // return true; if (!DoubleUtil.IsPositive(priceStep)) { return(true); } if (!DoubleUtil.IsPositive(lotTick)) { return(true); } m_buyPrice.Value = futPx + m_buyShift * priceStep; m_sellPrice.Value = futPx + m_sellShift * priceStep; // PROD-3687: Если выйти из метода слишком рано, то не будут заполнены контролы на UI if (!m_hedgeDelta) { return(true); } if (!permissionToWork) { // PROD-4568 - Если параметр блока говорит "можно", а на вход блока из скрипта подан запрет, // то нужно записать в лог значения этих параметров, чтобы не было вопросов потом. // См. также обсуждение на форуме: http://forum.tslab.ru/ubb/ubbthreads.php?ubb=showflat&Number=80364#Post80364 if (Context.Runtime.IsAgentMode) { string tName = (Context.Runtime.TradeName ?? "").Replace(Constants.HtmlDot, "."); string expiry = expirationDate.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture); string msg = String.Format("[{0}.{1}] Execution is blocked. Symbol:{2}; Expiry:{3}; HedgeDelta:{4}; Permission:{5}", MsgId, tName, underlyingSymbol, expiry, m_hedgeDelta, permissionToWork); m_context.Log(msg, MessageType.Warning, false); } return(true); } DateTime lastExec = LastExecution; //DateTime lastUpdate = optSer.UnderlyingAsset.FinInfo.LastUpdate; // В некоторых случаях слишком частое исполнение нам не подходит if ((lastUpdate - lastExec).TotalSeconds < m_minPeriod) { // Но надо проверять изменения в составе портфеля, чтобы вовремя ровнять дельту // НО КАК??? return(true); } #endregion Validate args // Если дельта уже лежит в заданных границах - просто выходим double dnEdge = m_targetDelta.Value - Math.Abs(m_doDelta.Value) + (1.0 - m_sensitivity); double upEdge = m_targetDelta.Value + Math.Abs(m_upDelta.Value) - (1.0 - m_sensitivity); // Пересчитываем пороги срабатывания в истинные лоты dnEdge *= lotTick; upEdge *= lotTick; if ((dnEdge < rawDelta) && (rawDelta < upEdge)) { //string msg = String.Format(CultureInfo.InvariantCulture, "[{0}] Delta is too low to hedge. Delta: {1}; TargetDelta: {2}; Sensitivity: {3}", // MsgId, rawDelta, m_targetDelta.Value, m_sensitivity); //context.Log(msg, logColor, true); return(true); } //var baseSecDesc = optSer.UnderlyingAsset.SecurityDescription; PositionsManager posMan = PositionsManager.GetManager(m_context); ISecurity sec = (from s in m_context.Runtime.Securities where (s.SecurityDescription != null) && baseSecDesc.Equals(s.SecurityDescription) select s).SingleOrDefault(); if (sec == null) { string msg = String.Format("[{0}] There is no security. Symbol: {1}", MsgId, underlyingSymbol); m_context.Log(msg, MessageType.Warning, true); return(true); } // PROD-6000 - Если в позиции вообще нет опционов, значит произошла какая-то ошибка if (!m_workWithoutOptions) { bool hasAnyOption = HasAnyOptionPosition(posMan, strikes); if (!hasAnyOption) { // В режиме агента обязательно логгируем, чтобы потом вопросов не было if (Context.Runtime.IsAgentMode) { string tName = (Context.Runtime.TradeName ?? "").Replace(Constants.HtmlDot, "."); string expiry = expirationDate.ToString(DateTimeFormatWithMs, CultureInfo.InvariantCulture); string msg = String.Format("[{0}.{1}] Execution is blocked. Symbol:{2}; Expiry:{3}; WorkWithoutOptions:{4}; HasAnyOption:{5}", MsgId, tName, underlyingSymbol, expiry, m_workWithoutOptions, hasAnyOption); m_context.Log(msg, MessageType.Warning, false); } return(true); } } // Здесь rawDelta и dnEdge ОБА в истинных лотах if (rawDelta <= dnEdge) { double diffLots = m_targetDelta.Value * lotTick - rawDelta; // Переводим в штуки LotTick-ов double diffLotTicks = diffLots / lotTick; int roundedLo = Math.Sign(diffLotTicks) * (int)Math.Floor(Math.Abs(diffLotTicks)); int roundedHi = Math.Sign(diffLotTicks) * (1 + (int)Math.Floor(Math.Abs(diffLotTicks))); int rounded; //if (Math.Abs(rawDelta + roundedLo - m_targetDelta.Value) <= Math.Abs(rawDelta + roundedHi - m_targetDelta.Value)) if (Math.Abs(roundedLo - diffLotTicks) <= Math.Abs(roundedHi - diffLotTicks)) { rounded = roundedLo; } else { rounded = roundedHi; } if (rounded > 0) { // [2015-07-15] Сдвиг заявки хеджа относительно рынка на заданную величину double px = futPx + m_buyShift * sec.Tick; string signalName; if (DoubleUtil.IsOne(lotTick)) { signalName = String.Format(CultureInfo.InvariantCulture, "F:{0}; Delta:{1}; TargetDelta:{2}", px, rawDelta, m_targetDelta.Value); } else { signalName = String.Format(CultureInfo.InvariantCulture, "F:{0}; Delta:{1}; TargetDelta:{2}; LotTick:{3}", px, rawDelta, m_targetDelta.Value * lotTick, lotTick); } m_context.Log(signalName, MessageType.Warning, false); posMan.BuyAtPrice(m_context, sec, Math.Abs(rounded * lotTick), px, "Delta BUY", signalName); m_context.StoreObject(VariableId + "_" + LastExecutionKey, now); } } // Здесь upEdge и rawDelta ОБА в истинных лотах else if (upEdge <= rawDelta) { double diffLots = m_targetDelta.Value * lotTick - rawDelta; // в этой ветке diff обычно отрицательный... // Переводим в штуки LotTick-ов double diffLotTicks = diffLots / lotTick; int roundedLo = Math.Sign(diffLotTicks) * (int)Math.Floor(Math.Abs(diffLotTicks)); int roundedHi = Math.Sign(diffLotTicks) * (1 + (int)Math.Floor(Math.Abs(diffLotTicks))); int rounded; if (Math.Abs(roundedLo - diffLotTicks) <= Math.Abs(roundedHi - diffLotTicks)) { rounded = roundedLo; } else { rounded = roundedHi; } if (rounded < 0) { // [2015-07-15] Сдвиг заявки хеджа относительно рынка на заданную величину double px = futPx + m_sellShift * sec.Tick; string signalName; if (DoubleUtil.IsOne(lotTick)) { signalName = String.Format(CultureInfo.InvariantCulture, "F:{0}; Delta:{1}; TargetDelta:{2}", px, rawDelta, m_targetDelta.Value); } else { signalName = String.Format(CultureInfo.InvariantCulture, "F:{0}; Delta:{1}; TargetDelta:{2}; LotTick:{3}", px, rawDelta, m_targetDelta.Value * lotTick, lotTick); } m_context.Log(signalName, MessageType.Warning, false); posMan.SellAtPrice(m_context, sec, Math.Abs(rounded * lotTick), px, "Delta SELL", signalName); m_context.StoreObject(VariableId + "_" + LastExecutionKey, now); } } return(true); }