| 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;
}
}
}