/// <summary>Integrate the series over the index range [index0,index1)</summary> public static double Integrate(this DataSeries series, Idx index0, Idx index1) { if (index0 > index1) { throw new Exception("Invalid index range: [{0},{1})".Fmt(index0, index1)); } var idx0 = (int)(index0 + series.Count - 1); var idx1 = (int)(index1 + series.Count - 1); idx0 = Maths.Clamp(idx0, 0, series.Count); idx1 = Maths.Clamp(idx1, 0, series.Count); var sum = 0.0; for (int i = idx0; i != idx1; ++i) { sum += series[i]; } return(sum); }
public StationaryPoint(Idx index, QuoteCurrency price, int sign) { Index = index; Price = price; Sign = sign; }
[DebuggerStepThrough] public bool Within(Idx min, Idx max) { return(Index.Within(min, max)); }
public FutureIdx(Idx idx, double confidence) : this() { Index = idx; Confidence = confidence; }
/// <summary>Returns the price peaks using a window with size 'window_size'</summary> public IEnumerable <Peak> FindPeaks(Idx iend) { // Create window buffers for the high/low prices var price_hi = new QuoteCurrency[WindowSize]; var price_lo = new QuoteCurrency[WindowSize]; for (int i = 0; i != WindowSize; ++i) { price_hi[i] = -double.MaxValue; price_lo[i] = +double.MaxValue; } // Look for peaks int d = 0, hh = -1, ll = -1, hcount = 0, lcount = 0; for (Idx i = iend; i-- != Instrument.IdxFirst; d = (d + 1) % WindowSize) { var candle = Instrument[i]; Beg = i; // Add the new price values price_hi[d] = candle.High; price_lo[d] = candle.Low; // Find the ring buffer index of the highest and lowest price var h = price_hi.IndexOfMaxBy(x => x); var l = price_lo.IndexOfMinBy(x => x); // If the high is the highest for the full window size, output it if (hh == h) { if (++hcount == WindowSize) { // Skip index == 0 because it's not a complete candle var idx = i + (d - hh + WindowSize) % WindowSize; if (Instrument.IdxLast - idx > 1) { yield return(new Peak(idx, price_hi[hh], true)); } hh = -1; hcount = 0; } } else { hh = h; hcount = 1; } // If the low is the lowest for the full window size, output it if (ll == l) { if (++lcount == WindowSize) { // Skip index == 0 because it's not a complete candle var idx = i + (d - ll + WindowSize) % WindowSize; if (Instrument.IdxLast - idx > 1) { yield return(new Peak(idx, price_lo[ll], false)); } ll = -1; lcount = 0; } } else { ll = l; lcount = 1; } } }
public Peak(Idx index, QuoteCurrency price, bool high) { Index = index; Price = price; High = high; }
// Notes: // - price is trending up if the lows are getting higher // - price is trending down if the highs are getting lower // - trend is unknown otherwise // - Break outs can be detected by comparing two sets of price peaks /// <summary>Find the highs and lows of the price</summary> /// <param name="instr">The instrument to find peaks in</param> /// <param name="iend">The last candle, i.e. look backwards from here</param> public PricePeaks(Instrument instr, Idx iend, int window_size = 5) { Instrument = instr; WindowSize = window_size; ConfirmTrend = 0.5; Beg = iend; End = iend; Highs = new List <Peak>(); Lows = new List <Peak>(); #region Find peaks { var threshold = ConfirmTrend * Instrument.MCS; var corr_hi = new Correlation(); var corr_lo = new Correlation(); // The last high/low encountered var hi = (Peak)null; var lo = (Peak)null; var done_hi = false; var done_lo = false; // Iterate through the peaks foreach (var pk in FindPeaks(iend)) { // Save the first peak as it might be a break out if (FirstPeak == null) { FirstPeak = pk; continue; } var last = pk.High ? hi : lo; var peaks = pk.High ? Highs : Lows; var corr = pk.High ? corr_hi : corr_lo; var trend = pk.High ? TrendHigh : TrendLow; var done = pk.High ? done_hi : done_lo; // First peak encountered? if (last == null) { // Just save the peak corr.Add(pk.Index, pk.Price); peaks.Add(pk); } // The trend has not been broken else if (!done) { // Second peak encountered if (trend == null) { // Form a trend line between the peaks if (pk.High) { TrendHigh = Monic.FromPoints(pk.Index, pk.Price, last.Index, last.Price); } else { TrendLow = Monic.FromPoints(pk.Index, pk.Price, last.Index, last.Price); } corr.Add(pk.Index, pk.Price); peaks.Add(pk); } // 3+ peak encountered, confirm trend strength else { // Get the predicted value from the trend line var p = trend.F(pk.Index); if (Math.Abs(p - pk.Price) < threshold) { // If within tolerance, the trend is confirmed corr.Add(pk.Index, pk.Price); if (pk.High) { TrendHigh = corr.LinearRegression; } else { TrendLow = corr.LinearRegression; } peaks.Add(pk); } else { if (pk.High) { done_hi = true; } else { done_lo = true; } // Otherwise, if the trend does not have 3 points, it is rejected if (peaks.Count < 3) { if (pk.High) { TrendHigh = null; } else { TrendLow = null; } } } } } // Save the peak as last if (pk.High) { hi = pk; } else { lo = pk; } // If the high and low trends are done, break the loop if (done_hi && done_lo) { break; } } } #endregion }
/// <summary>Get the second derivative at 'idx'</summary> public double ddF(Idx idx) { return(Curve.ddF(idx)); }
/// <summary>Get the predicted value</summary> public double this[Idx idx] { get { return(Curve.F(idx)); } }
/// <summary>Return the second derivative of the data series at 'index'</summary> public double SecondDerivative(Idx idx, int series = 0) { return(Source[series].SecondDerivative(idx)); }
/// <summary>Return the first derivative of the data series at 'index'</summary> public double FirstDerivative(Idx idx, int series = 0) { return(Source[series].FirstDerivative(idx)); }