Overall Statistics
Total Trades
95
Average Win
7.29%
Average Loss
-4.38%
Compounding Annual Return
6.180%
Drawdown
39.200%
Expectancy
0.417
Net Profit
89.483%
Sharpe Ratio
0.346
Loss Rate
47%
Win Rate
53%
Profit-Loss Ratio
1.66
Alpha
0.068
Beta
0.016
Annual Standard Deviation
0.199
Annual Variance
0.039
Information Ratio
0.04
Tracking Error
0.266
Treynor Ratio
4.364
Total Fees
$247.39
namespace QuantConnect.Rotation
{
	using QuantConnect.Algorithm.CSharp;
	
    /*
    *   QuantConnect University - Global Rotation by Michael Handschuh
    *
    *   From a list of ETF's which look at the global markets; always select the 
    *   best performing ETF assuming its momentum will continue.
    *
    *   Symbols are ranked by an objective function.
    *
    */
    public class QCUGlobalRotation : 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
            "IEV", // iShares S&P europe 350
            "EEM", // iShared MSCI emerging markets
            "ILF", // iShares S&P latin america
            "EPP"  // iShared MSCI Pacific ex-Japan
        };

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

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

        public override void Initialize()
        {
        	Profile.Enabled = true;
        	
            SetCash(25000);
            SetStartDate(2007, 1, 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);

                SymbolData.Add(new SymbolData
                {
                    Symbol = symbol,
                    OneMonthPerformance = oneMonthPerformance,
                    ThreeMonthPerformance = threeMonthPerformance
                });
            }
        }
        
        public override void OnEndOfAlgorithm()
        {
            Profile.PrintReport(this);
        }
        
        private void SetPositions(SymbolData bestGrowth)
        {
        	Profile.Begin("SetPositions");
        	
        	try
        	{
	        	if (bestGrowth.ObjectiveScore > 0)
	            {
	                if (Portfolio[bestGrowth.Symbol].Quantity == 0)
	                {
	                    Log("PREBUY>>LIQUIDATE>>");
	                    Liquidate();
	                } 
	                Log(">>BUY>>" + bestGrowth.Symbol + "@" + (100 * bestGrowth.OneMonthPerformance).ToString("00.00"));
	                decimal qty = Portfolio.Cash / Securities[bestGrowth.Symbol].Close;
	                MarketOrder(bestGrowth.Symbol, (int)qty);
	            }
	            else
	            {
	                // if no one has a good objective score then let's hold cash this month to be safe
	                Log(">>LIQUIDATE>>CASH");
	                Liquidate();
	            }
        	}
        	finally
        	{
        		Profile.End("SetPositions");
        	}
        }

        private bool first = true;
        public void OnData(TradeBars data)
        {
        	Profile.Begin("OnData");
        	
            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 = data.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();

                    SetPositions(bestGrowth);
                }
            }
            catch (Exception ex)
            {
                Error("OnTradeBar: " + ex.Message + "\r\n\r\n" + ex.StackTrace);
            }
            finally
            {
            	Profile.End("OnData");
            }
        }
    }

    class SymbolData
    {
        public string Symbol;

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

        public decimal ObjectiveScore
        {
            get
            {
            	Profile.Begin("ObjectiveScore");
            	
            	try
            	{
            		// we weight the one month performance higher
                	decimal weight1 = 100;
                	decimal weight2 = 75;

                	return (weight1 * OneMonthPerformance + weight2 * ThreeMonthPerformance) / (weight1 + weight2);
            	}
                finally
                {
                	Profile.End("ObjectiveScore");
                }
            }
        }
    }
}                        
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;

namespace QuantConnect.Algorithm.CSharp
{
    /// <summary>
    /// Instance version of Profiler.
    /// Starts enabled by default.
    /// </summary>
    public sealed class Profiler : IDisposable
    {
        private readonly object _myLock = new object();

        private struct MethodCall
        {
            public long StartTime;
            public CallNode Node;
        }

        private class CallNode
        {
            public string Name;
            public long TotalTime;
            public long TotalCalls;

            public CallNode Parent;
            public readonly List<CallNode> Children = new List<CallNode>();

            public long TotalTimeSelf
            {
                get { return TotalTime - Children.Sum(x => x.TotalTime); }
            }

            public List<CallNode> Siblings
            {
                get { return Parent != null ? Parent.Children : null; }
            }

            public double GetLocalInclusiveTimeFraction()
            {
                if (Parent == null)
                    return 1;

                var totalCallTime = Parent.TotalTime;
                if (totalCallTime == 0)
                {
                    if (Parent.Parent != null)
                        return 0;

                    totalCallTime = Siblings.Sum(x => x.TotalTime);
                    if (totalCallTime == 0)
                        return 0;
                }
                    
                var fraction = (double)TotalTime / totalCallTime;
                return fraction;
            }

            public double GetInclusiveTimeFraction()
            {
                var fraction = GetLocalInclusiveTimeFraction();

                var parent = Parent;
                while (parent != null)
                {
                    fraction *= parent.GetLocalInclusiveTimeFraction();
                    parent = parent.Parent;
                }

                return fraction;
            }

            public double GetLocalExclusiveTimeFraction()
            {
                if (Parent == null)
                    return 0;

                var totalCallTime = Parent.TotalTime;
                if (totalCallTime == 0)
                {
                    if (Parent.Parent != null)
                        return 0;

                    totalCallTime = Siblings.Sum(x => x.TotalTime);
                    if (totalCallTime == 0)
                        return 0;
                }
                var fraction = (double)TotalTimeSelf / totalCallTime;
                return fraction;
            }

            public double GetExclusiveTimeFraction()
            {
                var fraction = GetLocalExclusiveTimeFraction();

                var parent = Parent;
                while (parent != null)
                {
                    fraction *= parent.GetLocalInclusiveTimeFraction();
                    parent = parent.Parent;
                }

                return fraction;
            }
        }

        private readonly Stopwatch _stopwatch = new Stopwatch();
        private readonly ThreadLocal<Stack<MethodCall>> _callstack = new ThreadLocal<Stack<MethodCall>>();
        private readonly CallNode _root = new CallNode()
        {
            Name = "_root",
        };

        /// <summary>
        /// Not thread safe, enable/disable only when you know single thread is using!
        /// </summary>
        public bool Enabled { get; set; }

        public bool IsOpen()
        {
            lock (_myLock)
            {
                CheckCallstack();
                return _callstack.Value.Count > 0;
            }
        }

        public Profiler()
        {
            Enabled = true;
            _stopwatch.Start();
        }

        private void CheckCallstack()
        {
            if (!_callstack.IsValueCreated)
                _callstack.Value = new Stack<MethodCall>();
        }

        public void Begin(string method)
        {
            if (!Enabled)
                return;

            if (method == null || method == "")
                throw new ArgumentException("method");

            lock (_myLock)
            {
                CheckCallstack();
                var stack = _callstack.Value;

                var parent = stack.Count == 0 ? _root : stack.Peek().Node;
                var node = parent.Children.Find(x => x.Name == method);
                if (node == null)
                {
                    node = new CallNode()
                    {
                        Name = method,
                        Parent = parent,
                    };

                    parent.Children.Add(node);
                }

                node.TotalCalls += 1;

                var call = new MethodCall()
                {
                    Node = node,
                    StartTime = _stopwatch.ElapsedTicks,
                };

                stack.Push(call);
            }
        }

        public void End(string method = null)
        {
            if (!Enabled)
                return;

            lock (_myLock)
            {
                CheckCallstack();
                var stack = _callstack.Value;
                if (stack.Count == 0)
                    throw new InvalidOperationException("No corresponding entry call!");

                var call = stack.Pop();

                if (method != null && method != call.Node.Name)
                {
                    throw new InvalidOperationException("Expected end of " + method + ", entry was as " + call.Node.Name);
                }

                var elapsedMs = _stopwatch.ElapsedTicks - call.StartTime;

                call.Node.TotalTime += elapsedMs;
            }
        }

        private void PrintReport(Action<string> lineEmitter, CallNode node, string indent)
        {
            var line = indent + node.Name + ": "
                + node.GetInclusiveTimeFraction().ToString("P2")
                + " ("
                + node.GetExclusiveTimeFraction().ToString("P2")
                + ")";

            lineEmitter(line);

            indent += "  ";

            foreach (var child in node.Children)
            {
                PrintReport(lineEmitter, child, indent);
            }
        }

        public void PrintReport(Action<string> lineEmitter)
        {
            lock (_myLock)
            {
                lineEmitter("Stopwatch at " + _stopwatch.ElapsedMilliseconds + " ms and " + _stopwatch.ElapsedTicks + " ticks");

                foreach (var node in _root.Children)
                {
                    PrintReport(lineEmitter, node, "");
                }
            }
        }

        public void PrintReport(QCAlgorithm algo)
        {
            PrintReport(x => algo.Log(x));
        }

        public void Dispose()
        {
            _callstack.Dispose();
        }
    }

    /// <summary>
    /// Static single instance version of Profiler.
    /// Starts disabled by default, set Enabled to true to use.
    /// </summary>
    public static class Profile
    {
        private static Profiler _profiler = new Profiler()
        {
            Enabled = false
        };

        /// <summary>
        /// Not thread safe, enable/disable only when you know single thread is using!
        /// </summary>
        public static bool Enabled
        {
            get { return _profiler.Enabled; }
            set { _profiler.Enabled = value; }
        }

        public static bool IsOpen()
        {
            return _profiler.IsOpen();
        }

        /// <summary>
        /// Not thread safe, reset only when you know single thread is using!
        /// </summary>
        public static void Reset()
        {
            if (IsOpen())
                throw new InvalidOperationException("Trying to reset while profiler callstack is open!");

            bool enabled = _profiler.Enabled;
            _profiler.Dispose();
            _profiler = new Profiler();
            _profiler.Enabled = enabled;
        }

        public static void Begin(string method)
        {
            _profiler.Begin(method);
        }

        public static void End(string method = null)
        {
            _profiler.End(method);
        }

        public static void PrintReport(Action<string> lineEmitter)
        {
            _profiler.PrintReport(lineEmitter);
        }

        public static void PrintReport(QCAlgorithm algo)
        {
            _profiler.PrintReport(algo);
        }
    }
}