Overall Statistics
Total Trades
83
Average Win
4.45%
Average Loss
-3.32%
Compounding Annual Return
8.457%
Drawdown
20.800%
Expectancy
0.599
Net Profit
109.263%
Sharpe Ratio
0.607
Loss Rate
32%
Win Rate
68%
Profit-Loss Ratio
1.34
Alpha
0.095
Beta
-0.032
Annual Standard Deviation
0.152
Annual Variance
0.023
Information Ratio
0.052
Tracking Error
0.266
Treynor Ratio
-2.924
Total Fees
$622.94
namespace QuantConnect 
{   
    /*
    *   Author: Tomer Borenstein
    *   My attempt at whipping up an implementation of the "Global Market 
    *   Rotation" strategy. Original description of strategy is linked to 
    *   in the project notes.
    */
    
    public class SGMR : QCAlgorithm
    {
        private string currentMonth;
        private DateTime currentDay;
        private MyMomentum momentumETFA;
        private MyMomentum momentumETFB;
        private MyMomentum momentumETFC;

        string currentETF;
        string ETF1;
        string ETF2;
        string ETF3;
        
        public override void Initialize(){
			
            // start and End Date range for the backtest:
            SetStartDate(2007, 2, 1);         
            SetEndDate(DateTime.Now.Date.AddDays(-1));
            currentMonth = Time.ToString("MMM");
            currentETF = "";
            
            // cash allocation
            SetCash(100000);
            
//CHANGE SYMBOLS BELOW HERE -------------------------------------          
            ETF1 = "SPY";
            ETF2 = "IWM";
            ETF3 = "SHY";
// CHANGE SYMBOLS ABOVE HERE ------------------------------


            AddSecurity(SecurityType.Equity,ETF1, Resolution.Minute);
            AddSecurity(SecurityType.Equity, ETF2, Resolution.Minute);
            AddSecurity(SecurityType.Equity, ETF3, Resolution.Minute);

            
            // momentum over roughly 3 month period
            momentumETFA = new MyMomentum(ETF1, 50);
            momentumETFB = new MyMomentum(ETF2, 50);
            momentumETFC = new MyMomentum(ETF3, 50);

        }

        public void OnData(TradeBars data){   
            
            // day tick - add data to MyMomentum objects
            if(currentDay.Date != data.Time.Date){
                currentDay = data.Time;
                if(data.ContainsKey(ETF1)){
                    momentumETFA.add(data[ETF1].Close);    
            
                if(data.ContainsKey(ETF2)){
                    momentumETFB.add(data[ETF2].Close);  
                    
                    if(data.ContainsKey(ETF3)){
                    momentumETFC.add(data[ETF3].Close);  
                }
            }

            // month tick - use momentum to determine which ETF to invest in
            if(Time.ToString("MMM") != currentMonth){
                currentMonth = Time.ToString("MMM");
                string ETF = bestETF();
                if(currentETF != ETF){
                    Liquidate(); // cash out
                    // fully invest in best ETF if possible
                    if(data.ContainsKey(ETF)){
                        decimal cash = Portfolio.Cash;
                        decimal price = data[ETF].Close;
                        int quantity = (int)Math.Floor(cash/price);
                        Order(ETF, quantity);
                        Debug(Time.ToString("MMM") + ": invested in " + ETF + ".");
                    } else {
                        Debug(Time.ToString("MMM") + ": could not invest in " + ETF + ".");
                    }
                    currentETF = ETF;
                	}
            	}    
        	}
    	}
    }
    
        // returns the name of the ETF with the best return
        private string bestETF(){
            MyMomentum[] ETFs = new MyMomentum[]{momentumETFA, 
                                                 momentumETFB,
                                                 momentumETFC
        										  };
            string bestFund = "";
            decimal bestReturn = 0m;
            for(int i = 0; i < ETFs.Length; i++){
                MyMomentum mETF = ETFs[i];
                string fund = mETF.getName();
                decimal fundReturn = mETF.getReturn();
                if(bestFund == "" || bestReturn < fundReturn){
                    bestFund = fund;
                    bestReturn = fundReturn;
                }
            }
            return bestFund;
        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using QuantConnect.Securities;
using QuantConnect.Models;

namespace QuantConnect {

    // Author: Tomer Borenstein
    // MyMomentum - calculates a crude measure of an asset's return
    
    public class MyMomentum {
        private List<decimal> prices;
        private string name;
        private int window;
        
        public MyMomentum(string name, int window){
            this.prices = new List<decimal>();
            this.name = name;
            this.window = window;
        }
        
        public void add(decimal price){
            prices.Add(price);
            if(prices.Count > window){
                prices.RemoveAt(0);
            }
        }
        
        public string getName(){
            return name;
        }
        
        public decimal getReturn(){
            decimal start = prices[0];
            decimal end = prices[prices.Count - 1];
            return (end-start)/start;
        }
    }

}