Ejemplo n.º 1
0
        /// <summary>
        /// Calculate Kaufman's Adaptive Moving Average, as described here:
        /// <see href="https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:kaufman_s_adaptive_moving_average"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="erPeriod">period for efficiency ratio</param>
        /// <param name="fastEma">period for fast EMA</param>
        /// <param name="slowEma">period for slow EMA</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>KAMA as time series</returns>
        public static ITimeSeries <double> KAMA(this ITimeSeries <double> series, int erPeriod = 10, int fastEma = 2, int slowEma = 30,
                                                CacheId parentId = null, [CallerMemberName] string memberName    = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), erPeriod, fastEma, slowEma);

            // TODO: we should be able to remove the try/ catch blocks here
            return(IndicatorsBasic.BufferedLambda(
                       (v) =>
            {
                try
                {
                    double scFast = 2.0 / (1.0 + fastEma);
                    double scSlow = 2.0 / (1.0 + slowEma);

                    double change = Math.Abs(series[0] - series[erPeriod]);
                    double volatility = Enumerable.Range(0, erPeriod)
                                        .Sum(t => Math.Abs(series[t] - series[t + 1]));

                    double efficiencyRatio = change / Math.Max(1e-10, volatility);
                    double smoothingConstant = Math.Pow(efficiencyRatio * (scFast - scSlow) + scSlow, 2);

                    double r = smoothingConstant * (series[0] - v) + v;
                    return double.IsNaN(r) ? 0.0 : r;
                }
                catch (Exception)
                {
                    // we get here when we access bars too far in the past
                    return series[0];
                }
            },
                       series[0],
                       cacheId));
        }
        /// <summary>
        /// Calculate Pearson Correlation Coefficient.
        /// <see href="https://en.wikipedia.org/wiki/Pearson_correlation_coefficient"/>
        /// </summary>
        /// <param name="series">this time series</param>
        /// <param name="other">other time series</param>
        /// <param name="n">number of bars</param>
        /// <param name="subSample">distance between bars</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>correlation coefficient time series</returns>
        public static ITimeSeries <double> Correlation(this ITimeSeries <double> series, ITimeSeries <double> other, int n, int subSample = 1,
                                                       CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), other.GetHashCode(), n);

            var x = series;
            var y = other;

            double sum = n / 2.0 * (n + 1.0);

            return(IndicatorsBasic.BufferedLambda(
                       (v) =>
            {
                var avgX = Enumerable.Range(0, n)
                           .Average(t => x[t * subSample]);
                var avgY = Enumerable.Range(0, n)
                           .Average(t => y[t * subSample]);
                var covXY = Enumerable.Range(0, n)
                            .Sum(t => (x[t * subSample] - avgX) * (y[t * subSample] - avgY)) / n;
                var varX = Enumerable.Range(0, n)
                           .Sum(t => Math.Pow(x[t * subSample] - avgX, 2.0)) / n;
                var varY = Enumerable.Range(0, n)
                           .Sum(t => Math.Pow(y[t * subSample] - avgY, 2.0)) / n;
                var corr = covXY
                           / Math.Max(1e-99, Math.Sqrt(varX) * Math.Sqrt(varY));

                return corr;
            },
                       0.0,
                       cacheId));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Calculate Stochastic Oscillator, as described here:
        /// <see href="https://en.wikipedia.org/wiki/Stochastic_oscillator"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">oscillator period</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>Stochastic Oscillator as time series</returns>
        public static _StochasticOscillator StochasticOscillator(this ITimeSeries <double> series, int n = 14,
                                                                 CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);


            var container = Cache <_StochasticOscillator> .GetData(
                cacheId,
                () => new _StochasticOscillator());

            double hh = series
                        .Highest(n, cacheId)[0];

            double ll = series
                        .Lowest(n, cacheId)[0];

            double price = series[0];

            container.PercentK = IndicatorsBasic.BufferedLambda(
                v => 100.0 * (price - ll) / Math.Max(1e-10, hh - ll),
                50.0,
                cacheId);

            container.PercentD = container.PercentK
                                 .SMA(3, cacheId);

            return(container);
        }
        /// <summary>
        /// Calculate Covariance.
        /// <see href="https://en.wikipedia.org/wiki/Covariance"/>
        /// </summary>
        /// <param name="series">this time series</param>
        /// <param name="other">other time series</param>
        /// <param name="n">number of bars</param>
        /// <param name="subSample">distance between bars</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>covariance time series</returns>
        public static ITimeSeries <double> Covariance(this ITimeSeries <double> series, ITimeSeries <double> other, int n, int subSample = 1,
                                                      CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), other.GetHashCode(), n);

            var x = series;
            var y = other;

            return(IndicatorsBasic.BufferedLambda(
                       (v) =>
            {
                var avgX = Enumerable.Range(0, n)
                           .Average(t => x[t * subSample]);
                var avgY = Enumerable.Range(0, n)
                           .Average(t => y[t * subSample]);
                var covXY = Enumerable.Range(0, n)
                            .Sum(t => (x[t * subSample] - avgX) * (y[t * subSample] - avgY))
                            / (n - 1.0);

                return covXY;
            },
                       0.0,
                       cacheId));
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Calculate Money Flow Index indicator
        /// <see href="https://en.wikipedia.org/wiki/Money_flow_index"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">calculation period</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>MFI time series</returns>
        public static ITimeSeries <double> MoneyFlowIndex(this Instrument series, int n,
                                                          CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            var typicalPrice = series.TypicalPrice();

            var postiveMoneyFlow = IndicatorsBasic.BufferedLambda(
                prev => typicalPrice[0] > typicalPrice[1] ? typicalPrice[0] * series.Volume[0] : 0.0,
                0.0,
                cacheId);

            var negativeMoneyFlow = IndicatorsBasic.BufferedLambda(
                prev => typicalPrice[0] < typicalPrice[1] ? typicalPrice[0] * series.Volume[0] : 0.0,
                0.0,
                cacheId);

            return(postiveMoneyFlow
                   .SMA(n, cacheId)
                   .Divide(
                       postiveMoneyFlow
                       .SMA(n, cacheId)
                       .Add(
                           negativeMoneyFlow
                           .SMA(n, cacheId),
                           cacheId),
                       cacheId)
                   .Multiply(100.0, cacheId));
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Calculate subtraction of two time series.
        /// </summary>
        /// <param name="series1">time series #1</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <param name="series2">time series #2</param>
        /// <returns>time series #1 - time series #2</returns>
        public static ITimeSeries <double> Subtract(this ITimeSeries <double> series1, ITimeSeries <double> series2,
                                                    CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series1.GetHashCode(), series2.GetHashCode());

            return(IndicatorsBasic.Lambda(
                       (t) => series1[t] - series2[t],
                       cacheId));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Calculate Typical Price as described here:
        /// <see href="https://en.wikipedia.org/wiki/Typical_price"/>
        /// </summary>
        /// <param name="series">input instrument</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>typical price as time series</returns>
        public static ITimeSeries <double> TypicalPrice(this Instrument series,
                                                        CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode());

            return(IndicatorsBasic.Lambda(
                       (t) => (series.High[t] + series.Low[t] + series.Close[t]) / 3.0,
                       cacheId));
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Cast time series to double
        /// </summary>
        /// <param name="series">input series of long</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>output series of double</returns>
        public static ITimeSeries <double> ToDouble(this ITimeSeries <long> series,
                                                    CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode());

            return(IndicatorsBasic.Lambda(
                       (t) => (double)series[t],
                       cacheId));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Calculate addition of time series and constant value.
        /// </summary>
        /// <param name="series">time series</param>
        /// <param name="constValue">constant value</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>time series + constant value</returns>
        public static ITimeSeries <double> Add(this ITimeSeries <double> series, double constValue,
                                               CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), constValue.GetHashCode());

            return(IndicatorsBasic.Lambda(
                       (t) => series[t] + constValue,
                       cacheId));
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Accumulation/ distribution index as described here:
        /// <see href="https://en.wikipedia.org/wiki/Accumulation/distribution_index"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>accumulation/ distribution index as time series</returns>
        public static ITimeSeries <double> AccumulationDistributionIndex(this Instrument series,
                                                                         CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode());

            return(IndicatorsBasic.BufferedLambda(
                       (v) => v + series.Volume[0] * series.CLV()[0],
                       0.0,
                       cacheId));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Calculate simple momentum: m = p[0] / p[n] - 1
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">number of bars for regression</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>simple momentum, as time series</returns>
        public static ITimeSeries <double> SimpleMomentum(this ITimeSeries <double> series, int n = 21,
                                                          CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n.GetHashCode());

            return(IndicatorsBasic.BufferedLambda(
                       prev => series[0] / series[n] - 1.0,
                       0.0,
                       cacheId));
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Calculate Simple Moving Average as described here:
        /// <see href="https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">averaging length</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>SMA time series</returns>
        public static ITimeSeries <double> SMA(this ITimeSeries <double> series, int n,
                                               CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            return(IndicatorsBasic.BufferedLambda(
                       v => Enumerable.Range(0, n)
                       .Sum(t => series[t]) / n,
                       series[0],
                       cacheId));
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Calculate On-Balance Volume indicator.
        /// <see href="https://en.wikipedia.org/wiki/On-balance_volume"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>OBV time series</returns>
        public static ITimeSeries <double> OnBalanceVolume(this Instrument series,
                                                           CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode());

            return(IndicatorsBasic.BufferedLambda(
                       prev => series.Close[0] > series.Close[1]
                        ? prev + series.Volume[0]
                        : prev - series.Volume[0],
                       0,
                       cacheId));
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Calculate standard deviation, based on exponentially weighted filters. This is an
        /// incremental calculation, based on Tony Finch, which is very fast and efficient.
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">filtering length</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>variance as time series</returns>
        public static _SemiDeviation SemiDeviation(this ITimeSeries <double> series, int n = 10,
                                                   CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            var container = Cache <_SemiDeviation> .GetData(
                cacheId,
                () => new _SemiDeviation());

            container.Average = series.SMA(n);

            container.Downside = IndicatorsBasic.BufferedLambda(
                v =>
            {
                var downSeries = Enumerable.Range(0, n)
                                 .Where(t => series[t] < container.Average[0]);

                if (downSeries.Count() == 0)
                {
                    return(0.0);
                }
                else
                {
                    return(Math.Sqrt(downSeries
                                     .Average(t => Math.Pow(series[t] - container.Average[0], 2.0))));
                }
            }, 0.0,
                cacheId);

            container.Upside = IndicatorsBasic.BufferedLambda(
                v =>
            {
                var upSeries = Enumerable.Range(0, n)
                               .Where(t => series[t] > container.Average[0]);

                if (upSeries.Count() == 0)
                {
                    return(0.0);
                }
                else
                {
                    return(Math.Sqrt(upSeries
                                     .Average(t => Math.Pow(series[t] - container.Average[0], 2.0))));
                }
            }, 0.0,
                cacheId);

            return(container);
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Calculate True Range, non averaged, as described here:
        /// <see href="https://en.wikipedia.org/wiki/Average_true_range"/>.
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>True Range as time series</returns>
        public static ITimeSeries <double> TrueRange(this Instrument series,
                                                     CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode());

            return(IndicatorsBasic.Lambda(
                       (t) =>
            {
                double high = Math.Max(series[t].High, series[t + 1].Close);
                double low = Math.Min(series[t].Low, series[t + 1].Close);
                return high - low;
            },
                       cacheId));
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Return current drawdown in percent, as value between 0 and 1.
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">length of observation window</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>drawdown as time series</returns>
        public static ITimeSeries <double> Drawdown(this ITimeSeries <double> series, int n,
                                                    CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            // TODO: rewrite this, using buffered lambda, see MaxDrawdown
            return(IndicatorsBasic.Const(1.0, cacheId)
                   .Subtract(
                       series
                       .Divide(
                           series
                           .Highest(n, cacheId),
                           cacheId),
                       cacheId));
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Calculate return over maximum drawdown.
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">length of observation window</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>RoMaD</returns>
        public static ITimeSeries <double> ReturnOnMaxDrawdown(this ITimeSeries <double> series, int n,
                                                               CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            return(IndicatorsBasic.BufferedLambda(
                       (p) =>
            {
                double ret = series[0] / series[n] - 1.0;
                double dd = series.MaxDrawdown(n)[0];
                return ret / Math.Max(1e-3, dd);
            },
                       0.0,
                       cacheId));
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Calculate Average Directional Movement Index.
        /// <see href="https://en.wikipedia.org/wiki/Average_directional_movement_index"/>
        /// </summary>
        /// <param name="series">input OHLC time series</param>
        /// <param name="n">smoothing length</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>ADX time series</returns>
        public static ITimeSeries <double> ADX(this Instrument series, int n = 14,
                                               CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            var upMove   = Math.Max(0.0, series.High[0] - series.High[1]);
            var downMove = Math.Max(0.0, series.Low[1] - series.Low[0]);

            var plusDM = IndicatorsBasic.BufferedLambda(
                prev => upMove > downMove ? upMove : 0.0,
                0.0,
                cacheId);

            var minusDM = IndicatorsBasic.BufferedLambda(
                prev => downMove > upMove ? downMove : 0.0,
                0.0,
                cacheId);

            //var atr = series.AverageTrueRange(n);

            // +DI = 100 * Smoothed+DM / ATR
            var plusDI = plusDM
                         .EMA(n, cacheId);
            //.Divide(atr)
            //.Multiply(100.0);

            // -DI = 100 * Smoothed-DM / ATR
            var minusDI = minusDM
                          .EMA(n, cacheId);
            //.Divide(atr)
            //.Multiply(100.0);

            // DX = Abs(+DI - -DI) / (+DI + -DI)
            var DX = IndicatorsBasic.BufferedLambda(
                prev => 100.0 * Math.Abs(plusDI[0] - minusDI[0]) / (plusDI[0] + minusDI[0]),
                0.0,
                cacheId);

            // ADX = (13 * ADX[1] + DX) / 14
            var ADX = DX
                      .EMA(n, cacheId);

            //.Multiply(100.0);

            return(ADX);
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Calculate volatility estimate from recent trading range.
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">length of calculation window</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>volatility as time series</returns>
        public static ITimeSeries <double> VolatilityFromRange(this ITimeSeries <double> series, int n,
                                                               CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            return(IndicatorsBasic.BufferedLambda(
                       (v) =>
            {
                double hi = series.Highest(n)[0];
                double lo = series.Lowest(n)[0];

                return 0.80 * Math.Sqrt(1.0 / n) * Math.Log(hi / lo);
            },
                       0.0,
                       cacheId));
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Calculate Williams %R, as described here:
        /// <see href="https://en.wikipedia.org/wiki/Williams_%25R"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">period</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>Williams %R as time series</returns>
        public static ITimeSeries <double> WilliamsPercentR(this ITimeSeries <double> series, int n = 10,
                                                            CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            return(IndicatorsBasic.BufferedLambda(
                       (v) =>
            {
                double hh = series.Highest(n)[0];
                double ll = series.Lowest(n)[0];
                double price = series[0];
                return -100.0 * (hh - price) / Math.Max(1e-10, hh - ll);
            },
                       -50.0,
                       cacheId));
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Calculate Exponential Moving Average, as described here:
        /// <see href="https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">averaging length</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>EMA time series</returns>
        public static ITimeSeries <double> EMA(this ITimeSeries <double> series, int n,
                                               CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);


            double alpha = 2.0 / (Math.Max(1, n) + 1);

            return(IndicatorsBasic.BufferedLambda(
                       (v) =>
            {
                double r = alpha * (series[0] - v) + v;
                return double.IsNaN(r) ? 0.0 : r;
            },
                       series[0],
                       cacheId));
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Calculate equally-weighted market benchmark.
        /// </summary>
        /// <param name="market">enumerable of instruments making up market</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>benchmark time series</returns>
        public static ITimeSeries <double> Benchmark(this IEnumerable <Instrument> market,
                                                     CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            // TODO: need to figure out, if we want to include the market in the calcualtion
            //       of the cache id. for now, we decided to _not_ include the market,
            //       as instruments included might change, for the _same_ market
            var cacheId = new CacheId(parentId, memberName, lineNumber
                                      );

            return(IndicatorsBasic.BufferedLambda(
                       (p) =>
            {
                double todaysLogReturn = market
                                         .Average(i => i.Close.LogReturn()[0]);
                return p * Math.Exp(todaysLogReturn);
            },
                       1.0,
                       cacheId));
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Calculate Sharpe Ratio, as described here:
        /// <see href="https://en.wikipedia.org/wiki/Sharpe_ratio"/>
        /// </summary>
        /// <param name="series"></param>
        /// <param name="riskFreeRate"></param>
        /// <param name="n"></param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns></returns>
        public static ITimeSeries <double> SharpeRatio(this ITimeSeries <double> series, ITimeSeries <double> riskFreeRate, int n,
                                                       CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), riskFreeRate.GetHashCode(), n);

            var excessReturn = series
                               .Return(cacheId)
                               .Subtract(riskFreeRate
                                         .Return(cacheId),
                                         cacheId);

            return(excessReturn
                   .EMA(n, cacheId)
                   .Divide(excessReturn
                           .FastStandardDeviation(n, cacheId)
                           .Max(IndicatorsBasic.Const(1e-10, cacheId), cacheId),
                           cacheId));
        }
Ejemplo n.º 24
0
        /// <summary>
        /// Return maximum drawdown.
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">length of observation window</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>maximum drawdown as time series</returns>
        public static ITimeSeries <double> MaxDrawdown(this ITimeSeries <double> series, int n,
                                                       CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            return(IndicatorsBasic.BufferedLambda(
                       (p) =>
            {
                double highestHigh = 0.0;
                double maxDrawdown = 0.0;
                for (int t = n - 1; t >= 0; t--)
                {
                    highestHigh = Math.Max(highestHigh, series[t]);
                    maxDrawdown = Math.Max(maxDrawdown, 1.0 - series[t] / highestHigh);
                }
                return maxDrawdown;
            },
                       0.0,
                       cacheId));
        }
Ejemplo n.º 25
0
        /// <summary>
        /// Calculate historical standard deviation.
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">length</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>standard deviation as time series</returns>
        public static ITimeSeries <double> StandardDeviation(this ITimeSeries <double> series, int n = 10,
                                                             CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            // see https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance

            // TODO: (1) rewrite using Linq. See WMA implementation
            //       (2) we should be able to remove try/catch blocks
            return(IndicatorsBasic.BufferedLambda(
                       (v) =>
            {
                double sum = 0.0;
                double sum2 = 0.0;
                int num = 0;

                try
                {
                    for (int t = 0; t < n; t++)
                    {
                        sum += series[t];
                        sum2 += series[t] * series[t];
                        num++;
                    }
                }
                catch (Exception)
                {
                    // we get here when we access bars too far in the past
                }

                double variance = num > 1
                        ? (sum2 - sum * sum / num) / (num - 1)
                        : 0.0;

                return Math.Sqrt(Math.Max(0.0, variance));
            },
                       0.0,
                       cacheId));
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Calculate logarithmic momentum: m = Ln(p[0] / p[n])
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">number of bars for regression</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>log momentum, as time series</returns>
        public static ITimeSeries <double> LogMomentum(this ITimeSeries <double> series, int n = 21,
                                                       CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n.GetHashCode());

#if true
            return(IndicatorsBasic.BufferedLambda(
                       prev => Math.Log(series[0] / series[n]),
                       0.0,
                       cacheId));
#else
            // retired 04/02/2019
            return(series
                   .Divide(series
                           .Delay(n, cacheId)
                           .Max(1e-10, cacheId),
                           cacheId)
                   .Log(cacheId)
                   .Divide(n, cacheId));
#endif
        }
Ejemplo n.º 27
0
        /// <summary>
        /// Calculate Bollinger Bands, as described here:
        /// <see href="https://traderhq.com/ultimate-guide-to-bollinger-bands/"/>.
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">length of calculation</param>
        /// <param name="stdev">width of bands</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>Bollinger Band time series</returns>
        public static _BollingerBands BollingerBands(this ITimeSeries <double> series, int n = 20, double stdev    = 2.0,
                                                     CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n, stdev.GetHashCode());

            var container = Cache <_BollingerBands> .GetData(
                cacheId,
                () => new _BollingerBands());

            var stdevSeries = series.StandardDeviation(n, cacheId).Multiply(stdev, cacheId);

            container.Middle   = series.SMA(n, cacheId);
            container.Upper    = container.Middle.Add(stdevSeries, cacheId);
            container.Lower    = container.Middle.Subtract(stdevSeries, cacheId);
            container.PercentB = IndicatorsBasic.BufferedLambda(
                prev => (series[0] - container.Lower[0]) / Math.Max(1e-10, container.Upper[0] - container.Lower[0]),
                0.0,
                cacheId);

            return(container);
        }
Ejemplo n.º 28
0
        /// <summary>
        /// Calculate True Strength Index of input time series, as described here:
        /// <see href="https://en.wikipedia.org/wiki/True_strength_index"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="r">smoothing period for momentum</param>
        /// <param name="s">smoothing period for smoothed momentum</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>TSI time series</returns>
        public static ITimeSeries <double> TSI(this ITimeSeries <double> series, int r = 25, int s           = 13,
                                               CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), r, s);

            ITimeSeries <double> momentum = series
                                            .Return(cacheId);

            double numerator = momentum
                               .EMA(r, cacheId)
                               .EMA(s, cacheId)[0];

            double denominator = momentum
                                 .AbsValue(cacheId)
                                 .EMA(r, cacheId)
                                 .EMA(s, cacheId)[0];

            return(IndicatorsBasic.BufferedLambda(
                       v => 100.0 * numerator / Math.Max(1e-10, denominator),
                       0.5,
                       cacheId));
        }
Ejemplo n.º 29
0
        /// <summary>
        /// Calculate Relative Strength Index, as described here:
        /// <see href="https://en.wikipedia.org/wiki/Relative_strength_index"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">smoothing period</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>RSI time series</returns>
        public static ITimeSeries <double> RSI(this ITimeSeries <double> series, int n = 14,
                                               CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            ITimeSeries <double> returns = series.Return(cacheId);

            double avgUp = returns
                           .Max(0.0, cacheId)
                           .EMA(n, cacheId)[0];

            double avgDown = -returns
                             .Min(0.0, cacheId)
                             .EMA(n, cacheId)[0];

            double rs = avgUp / Math.Max(1e-10, avgDown);

            return(IndicatorsBasic.BufferedLambda(
                       v => 100.0 - 100.0 / (1 + rs),
                       50.0,
                       cacheId));
        }
Ejemplo n.º 30
0
        /// <summary>
        /// Calculate Commodity Channel Index of input time series, as described here:
        /// <see href="https://en.wikipedia.org/wiki/Commodity_channel_index"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">averaging length</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>CCI time series</returns>
        public static ITimeSeries <double> CCI(this ITimeSeries <double> series, int n = 20,
                                               CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            return(IndicatorsBasic.BufferedLambda(
                       (v) =>
            {
                ITimeSeries <double> delta = series
                                             .Subtract(
                    series
                    .SMA(n, cacheId),
                    cacheId);

                ITimeSeries <double> meanDeviation = delta
                                                     .AbsValue(cacheId)
                                                     .SMA(n, cacheId);

                return delta[0] / Math.Max(1e-10, 0.015 * meanDeviation[0]);
            },
                       0.5,
                       cacheId));
        }