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 { /* Simple 3 ETF Momentum Rotation - script mod by dime 03/06/2016 * Based on Tomer Borenstein's "Global Market Rotation" */ 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 previous 50 days 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 != Time.Date){ currentDay = 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; } } }