Overall Statistics
Total Trades
1355
Average Win
0.56%
Average Loss
-0.23%
Compounding Annual Return
7.923%
Drawdown
16.500%
Expectancy
0.080
Net Profit
27.173%
Sharpe Ratio
0.557
Probabilistic Sharpe Ratio
16.250%
Loss Rate
69%
Win Rate
31%
Profit-Loss Ratio
2.46
Alpha
0.072
Beta
-0.076
Annual Standard Deviation
0.108
Annual Variance
0.012
Information Ratio
-0.433
Tracking Error
0.223
Treynor Ratio
-0.795
Total Fees
$3176.17
Estimated Strategy Capacity
$4400000.00
Lowest Capacity Asset
TLT SGNKIKYGE9NP
namespace QuantConnect.Algorithm.CSharp
{
    public class VirtualLightBrownOwl : QCAlgorithm
    {
    	// Dictionary to hold Symbol Data
		private Dictionary<Symbol, SymbolData> _symbolData = new ();

        public override void Initialize()
        {
	        SetStartDate(2019, 1, 1);  // Set Start Date
	        SetCash(100000);           // Set Strategy Cash
        
        	var tickers = new[] {"SPY", "TLT"};
        	
        	foreach (var ticker in tickers)
        	{
        		// Add equity data
            	var symbol = AddEquity(ticker, Resolution.Minute).Symbol;
	            // Create symbol data for respective symbol
            	_symbolData[symbol] = new SymbolData(this, symbol);
        	}
        }

		private class SymbolData
		{
			private QCAlgorithm _algorithm;
			private Symbol _symbol;
			private SimpleMovingAverage _sma = new SimpleMovingAverage(14);
			private RollingWindow<TradeBar> _barWindow = new RollingWindow<TradeBar>(2);
			
    		public bool IsReady => _sma.IsReady && _barWindow.IsReady;
			
			public SymbolData(QCAlgorithm algorithm, Symbol symbol)
			{
				_algorithm = algorithm;
	        	_symbol = symbol;
	        	
	        	// Define our consolidator for 30 min bars
                var hourlyConsolidator = new TradeBarConsolidator(Custom);
		        hourlyConsolidator.DataConsolidated += OnDataConsolidated;
        		algorithm.SubscriptionManager.AddConsolidator(_symbol, hourlyConsolidator);
        		
        		// Register indicator to our consolidator
        		algorithm.RegisterIndicator(_symbol, _sma, hourlyConsolidator);
			}
		
			private CalendarInfo Custom(DateTime dt)
			{
				var period = TimeSpan.FromHours(1);
				var start = dt.AddMinutes(30-dt.Minute);
        		if (start > dt) start -= period;
        		return new CalendarInfo(start, period);
			}
			
			private void OnDataConsolidated(object sender, TradeBar bar)
			{
				_barWindow.Add(bar);
				
				if (!IsReady) return;
				
				var lastBar = _barWindow[1];
            	var currentBar = _barWindow[0];
            	
            	// Buy if there is a long cross over
            	if (lastBar.Close < _sma && currentBar.Close > _sma)
            	{
                	_algorithm.SetHoldings(_symbol, 0.5);
            	}
            	else if (lastBar.Close > _sma && currentBar.Close < _sma)
            	{
            		_algorithm.SetHoldings(_symbol, -0.5);
            	}
			}
		}
    }
}