Overall Statistics
Total Trades
21
Average Win
21.07%
Average Loss
-11.50%
Compounding Annual Return
-0.237%
Drawdown
54.200%
Expectancy
0.133
Net Profit
-4.081%
Sharpe Ratio
0.085
Loss Rate
60%
Win Rate
40%
Profit-Loss Ratio
1.83
Alpha
0.019
Beta
-0.032
Annual Standard Deviation
0.195
Annual Variance
0.038
Information Ratio
-0.227
Tracking Error
0.281
Treynor Ratio
-0.512
Total Fees
$88.91
/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

namespace QuantConnect.Indicators
{
    /// <summary> 
    /// Oscillator indicator that measures momentum and mean-reversion over a specified
    /// period n.
    /// Source: Harris, Michael. "Momersion Indicator." Price Action Lab.,
    ///             13 Aug. 2015. Web. <http://www.priceactionlab.com/Blog/2015/08/momersion-indicator/>.
    /// </summary>
    public class MomersionIndicator : WindowIndicator<IndicatorDataPoint>
    {
        /// <summary>
        /// The minimum observations needed to consider the indicator ready. After that observation
        /// number is reached, the indicator will continue gathering data until the full period.
        /// </summary>
        private int? _minPeriod;

        /// <summary>
        /// The final full period used to estimate the indicator.
        /// </summary>
        private int _fullPeriod;

        /// <summary>
        /// The rolling window used to store the momentum.
        /// </summary>
        private RollingWindow<decimal> _multipliedDiffWindow;

        /// <summary>
        /// Initializes a new instance of the <see cref="MomersionIndicator"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="minPeriod">The minimum period.</param>
        /// <param name="fullPeriod">The full period.</param>
        /// <exception cref="System.ArgumentException">The minimum period should be greater of 3.;minPeriod</exception>
        public MomersionIndicator(string name, int? minPeriod, int fullPeriod)
            : base(name, 3)
        {
            _fullPeriod = fullPeriod;
            _multipliedDiffWindow = new RollingWindow<decimal>(fullPeriod);
            if (minPeriod < 4)
            {
                throw new ArgumentException("The minimum period should be greater of 3.", "minPeriod");
            }
            _minPeriod = minPeriod;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MomersionIndicator"/> class.
        /// </summary>
        /// <param name="minPeriod">The minimum period.</param>
        /// <param name="fullPeriod">The full period.</param>
        public MomersionIndicator(int minPeriod, int fullPeriod)
            : this("Momersion_" + fullPeriod, minPeriod, fullPeriod)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MomersionIndicator"/> class.
        /// </summary>
        /// <param name="fullPeriod">The full period.</param>
        public MomersionIndicator(int fullPeriod)
            : this("Momersion_" + fullPeriod, null, fullPeriod)
        {
        }
        

        /// <summary>
        /// Gets a flag indicating when this indicator is ready and fully initialized
        /// </summary>
        public override bool IsReady
        {
            get
            {
                if (_minPeriod.HasValue)
                {
                    return _multipliedDiffWindow.Count >= _minPeriod;
                }
                else
                {
                    return _multipliedDiffWindow.IsReady;
                }
            }
        }

        /// <summary>
        /// Resets this indicator to its initial state
        /// </summary>
        public override void Reset()
        {
            base.Reset();
            _multipliedDiffWindow.Reset();
        }


        /// <summary>
        /// Computes the next value of this indicator from the given state
        /// </summary>
        /// <param name="window"></param>
        /// <param name="input">The input given to the indicator</param>
        /// <returns>
        /// A new value for this indicator
        /// </returns>
        protected override decimal ComputeNextValue(IReadOnlyWindow<IndicatorDataPoint> window, IndicatorDataPoint input)
        {
            int Mc = 0;
            int MRc = 0;
            decimal momersion;

            if (window.Count >= 3) _multipliedDiffWindow.Add((window[0] - window[1]) * (window[1] - window[2]));

            if (this.IsReady)
            {
                Mc = _multipliedDiffWindow.Count(obs => obs > 0);
                MRc = _multipliedDiffWindow.Count(obs => obs < 0);
                momersion = 100m * Mc / (Mc + MRc);
            }
            else
            {
                momersion = 50m;
            }

            Current = new IndicatorDataPoint(input.Time, momersion);
            return this.Current;
        }
    }
}
/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

namespace QuantConnect
{   
    public class MomersionAlgorithm : QCAlgorithm
    {
        string symbol = "SPY";
        MomersionIndicator SlowMomersion;
        MomersionIndicator FastMomersion;
        SimpleMovingAverage MomersionSMA;
        
        public override void Initialize()
        {
            SetStartDate(1998, 01, 02);  //Set Start Date
            SetEndDate(2015, 07, 31);    //Set End Date
            SetCash(100000);             //Set Strategy Cash
            
            AddSecurity(SecurityType.Equity, symbol, Resolution.Daily);

            SlowMomersion = new MomersionIndicator(250);
            RegisterIndicator(symbol, SlowMomersion, Resolution.Daily, Field.Close);
            MomersionSMA = new SimpleMovingAverage(20).Of(SlowMomersion);

            FastMomersion = new MomersionIndicator(20);
            RegisterIndicator(symbol, FastMomersion, Resolution.Daily, Field.Close);
        }

        /// <summary>
        /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        /// </summary>
        /// <param name="data">Slice object keyed by symbol containing the stock data</param>
        public override void OnData(Slice data)
        {
        	#region Slow smoothed Momersion 
			//if (!MomersionSMA.IsReady) return;
            
            //if (!Portfolio[symbol].HoldStock && MomersionSMA.Current.Value < 45m)
            //{
            //    SetHoldings(symbol, 1d);
            //}

            //if (Portfolio[symbol].HoldStock && MomersionSMA.Current.Value > 55m)
            //{
            //    Liquidate(symbol);
            //}
            #endregion

            #region Fast Momersion
            if (!FastMomersion.IsReady) return;

            bool shortSignal = FastMomersion.Current.Value > 70;
            bool longSignal = FastMomersion.Current.Value < 30;

            if (Portfolio[symbol].HoldStock)
            {
                if ((Portfolio[symbol].IsLong  && shortSignal) ||
                    (Portfolio[symbol].IsShort && longSignal))
                    Liquidate(symbol);
            }
            else
            {
                if (longSignal) SetHoldings(symbol, 1);
                if (shortSignal) SetHoldings(symbol, -1);
            }
            #endregion
        }
    }
}