Overall Statistics
namespace QuantConnect.Rotation
{
    public class GlobalRotation : QCAlgorithm
    {
        // we'll use this to tell us when the month has ended
        DateTime LastRotationTime = DateTime.MinValue;
        TimeSpan RotationInterval = TimeSpan.FromDays(30);

        // these are the growth symbols we'll rotate through
        List<string> GrowthSymbols = new List<string>
        {
            "MDY", // US S&P mid cap 400
            "EWJ", // Japan
            "IEV", // iShares S&P europe 350
            "EEM", // iShared MSCI emerging markets
            "ILF", // iShares S&P latin america
            "EPP", // iShared MSCI Pacific ex-Japan
            "IYR", // US REIT
            "RWX", // International REIT
            "EDV", // Vangaurd TSY 25yr+
            "IEF", // Intermediate Treasury
            "DBC", // Commodities
            "GLD"  // Gold
        };

        // these are the safety symbols we go to when things are looking bad for growth
        List<string> SafetySymbols = new List<string>
        {
            "SHY"  // Barclays Low Duration TSY
        };

        // we'll hold some computed data in these guys
        List<SymbolData> SymbolData = new List<SymbolData>();

        public override void Initialize()
        {
            SetCash(10000);
            SetStartDate(2007, 1, 1);
            SetEndDate(2017, 5, 1);

            foreach (var symbol in GrowthSymbols.Union(SafetySymbols))
            {
                // ideally we would use daily data
                AddSecurity(SecurityType.Equity, symbol, Resolution.Minute);
                var oneMonthPerformance = MOM(symbol, 30, Resolution.Daily);
                var threeMonthPerformance = MOM(symbol, 90, Resolution.Daily);
                var sixMonthPerformance = MOM(symbol, 180, Resolution.Daily);
                var twelveMonthPerformance = MOM(symbol, 360, Resolution.Daily);

                SymbolData.Add(new SymbolData
                {
                    Symbol = symbol,
                    OneMonthPerformance = oneMonthPerformance,
                    ThreeMonthPerformance = threeMonthPerformance,
                    SixMonthPerformance = sixMonthPerformance,
                    TwelveMonthPerformance = twelveMonthPerformance
                });
            }
        }

        private bool first = true;
        public void OnData(TradeBars data)
        {
            try
            {
                // the first time we come through here we'll need to do some things such as allocation
                // and initializing our symbol data
                if (first)
                {
                    first = false;
                    LastRotationTime = data.Time;
                    return;
                }

                var delta = Time.Subtract(LastRotationTime);
                if (delta > RotationInterval)
                {
                    LastRotationTime = data.Time;

                    // pick which one is best from growth and safety symbols
                    var orderedObjScores = SymbolData.OrderByDescending(x => x.ObjectiveScore).ToList();
                    foreach (var orderedObjScore in orderedObjScores)
                    {
                        Log(">>SCORE>>" + orderedObjScore.Symbol + ">>" + orderedObjScore.ObjectiveScore);
                    }
                    var bestGrowth = orderedObjScores.First();

                    if (bestGrowth.ObjectiveScore > 0)
                    {
                        if (Portfolio[bestGrowth.Symbol].Quantity == 0)
                        {
                            Log("PREBUY>>LIQUIDATE>>");
                            Liquidate();
                        }
                        Log(">>BUY>>" + bestGrowth.Symbol + "@" + (100 * bestGrowth.OneMonthPerformance).ToString("00.00"));
                        SetHoldings(bestGrowth.Symbol, 1.0);
                    }
                    else
                    {
                        // if no one has a good objective score then let's hold cash this month to be safe
                        Log(">>LIQUIDATE>>CASH");
                        Liquidate();
                    }
                }
            }
            catch (Exception ex)
            {
                Error("OnTradeBar: " + ex.Message + "\r\n\r\n" + ex.StackTrace);
            }
        }
    }

    class SymbolData
    {
        public string Symbol;

        public Momentum OneMonthPerformance { get; set; }
        public Momentum ThreeMonthPerformance { get; set; }
        public Momentum SixMonthPerformance { get; set; }
        public Momentum TwelveMonthPerformance { get; set; }

        public decimal ObjectiveScore
        {
            get
            {
                // we weight the one month performance higher
                decimal weight1 = 100;
                decimal weight2 = 100;
                decimal weight3 = 100;
                decimal weight4 = 100;

                return (weight1 * OneMonthPerformance + weight2 * ThreeMonthPerformance + weight3 * SixMonthPerformance + weight4 * TwelveMonthPerformance) / (weight1 + weight2 + weight3 + weight4);
            }
        }
    }
}