Overall Statistics
Total Trades
512
Average Win
0.71%
Average Loss
-0.42%
Compounding Annual Return
10.961%
Drawdown
9.000%
Expectancy
0.820
Net Profit
150.244%
Sharpe Ratio
1.154
Probabilistic Sharpe Ratio
70.157%
Loss Rate
32%
Win Rate
68%
Profit-Loss Ratio
1.66
Alpha
0.072
Beta
0.022
Annual Standard Deviation
0.064
Annual Variance
0.004
Information Ratio
-0.117
Tracking Error
0.134
Treynor Ratio
3.435
Total Fees
$512.00
using System.Collections.Generic;
using QuantConnect.Data;
using System;
using System.Collections;
using QuantConnect.Orders;
using System.Globalization;
using QuantConnect.Data.Market;
using QuantConnect.Algorithm;
using QuantConnect.Securities;
using QuantConnect.Brokerages;

namespace QuantConnect
{
	public class PortfolioOfStrategies : QCAlgorithm
    {
    	// Algorithm parameters
        private int mStartYear = 							2011;
        public int mStartMonth = 							1;
        public int mStartDay = 								28;
        private decimal mStartingCash = 					10000;
        private Resolution mResolution = 					Resolution.Minute; // Hourly or more frequent. Daily and up bugs.
        private decimal mLeverage = 						0.95m;
        private bool mRebalanceOnLaunch = 					true; // Whether the algorithms should trigger a rebalance when launching the algorithm (true) or wait until the next rebalance period (false)
        protected decimal mAvoidRebalancesBelowThisAmount = 500.0m; // 500 is a good value. Value, in dollars, under which small rebalances will be ignored to cut on fees.
        private decimal mAllocationRatioUIS = 				1.0m;
        private decimal mAllocationRatioUISZIV = 			0.0m;
        private decimal mAllocationRatioBRS =				0.0m;
        private decimal mAllocationRatioGLDUSD =			0.0m;
        private decimal mAllocationRatioMYRS = 				0.0m;
        private decimal mAllocationRatioNASDAQ_LI_SIGNALS = 0.0m;
		private decimal mAllocationRatioGLD_LI_SIGNALS = 	0.0m;
        private decimal mAllocationRatioUIS_LI_SIGNALS = 	0.0m;
        private decimal mAllocationRatioFFA = 				0.0m;
        private decimal mAllocationRatioEMPTYALGO = 		0.0m;
        private decimal mAllocationRatioSRCTEST =			0.0m;
        
        //Other variables
        public bool mBacktestDatesOverriden =		false;
        private List<SubAlgorithm> mSubAlgorithms = null;
        EquityExchange mEquityMarket = new EquityExchange();
        

        public override void Initialize()
        {
	        Portfolio.MarginCallModel = MarginCallModel.Null;
	        SetCash(mStartingCash);
	        SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage);
            
            // Request SPY and USDCAD data
            AddSecurity(SecurityType.Equity, "SPY", mResolution, true, 3, false);
            AddSecurity(SecurityType.Forex, "USDCAD", mResolution, true, 3, false);
            
            // Instantiate our subalgorithm classes
            mSubAlgorithms = new List<SubAlgorithm>();
            mSubAlgorithms.Add(new UIS				(this, mResolution, mAllocationRatioUIS, 				mStartYear, mRebalanceOnLaunch));
            mSubAlgorithms.Add(new UISZIV			(this, mResolution, mAllocationRatioUISZIV, 			mStartYear, mRebalanceOnLaunch));
            mSubAlgorithms.Add(new MYRS				(this, mResolution, mAllocationRatioMYRS, 				mStartYear, mRebalanceOnLaunch));
            mSubAlgorithms.Add(new BRS				(this, mResolution, mAllocationRatioBRS, 				mStartYear, mRebalanceOnLaunch));
            mSubAlgorithms.Add(new GLDUSD			(this, mResolution, mAllocationRatioGLDUSD, 			mStartYear, mRebalanceOnLaunch));
            mSubAlgorithms.Add(new NASDAQ_LI_SIGNALS(this, mResolution, mAllocationRatioNASDAQ_LI_SIGNALS, 	mStartYear, mRebalanceOnLaunch));
            mSubAlgorithms.Add(new GLD_LI_SIGNALS	(this, mResolution, mAllocationRatioGLD_LI_SIGNALS, 	mStartYear, mRebalanceOnLaunch));
            mSubAlgorithms.Add(new UIS_LI_SIGNALS	(this, mResolution, mAllocationRatioUIS_LI_SIGNALS, 	mStartYear, mRebalanceOnLaunch));
            mSubAlgorithms.Add(new FFA				(this, mResolution, mAllocationRatioFFA, 				mStartYear, mRebalanceOnLaunch));
            mSubAlgorithms.Add(new EMPTYALGO		(this, mResolution, mAllocationRatioEMPTYALGO, 			mStartYear, mRebalanceOnLaunch));
            mSubAlgorithms.Add(new Test_SRC			(this, mResolution, mAllocationRatioSRCTEST, 			mStartYear, mRebalanceOnLaunch));
        
        	// Initialize the subalgorithms
        	foreach(SubAlgorithm wSubAlgorithm in mSubAlgorithms)
        	{
        		if(wSubAlgorithm.mAllocationRatio > 0.01m)
        		{
        			wSubAlgorithm.Initialize(mLeverage * wSubAlgorithm.mAllocationRatio * (Portfolio.TotalPortfolioValue - GetUnconvertedCadValueInUsd()));
        		}
        	}
        	
        	// Set up our analysis span (unless a strategy has overridden them)
        	if (!mBacktestDatesOverriden)
        	{
        		SetStartDate(mStartYear, mStartMonth, mStartDay);
	            SetEndDate(DateTime.Today.AddDays(-1));
        	}
        }
        
        public void OnData(TradeBars data)
        {
        	if(mEquityMarket.DateTimeIsOpen(Time))
        	{
        		// Set allocation of money in the different subalgorithms, and dispatch them
	            bool wAllAlgosCommunicatedDesiredAllocation = true;
	        	foreach(SubAlgorithm wSubAlgorithm in mSubAlgorithms)
	        	{
	        		if(wSubAlgorithm.mAllocationRatio > 0.01m)
	        		{
	        			wSubAlgorithm.SetAllocationAmount(mLeverage * wSubAlgorithm.mAllocationRatio * (Portfolio.TotalPortfolioValue - GetUnconvertedCadValueInUsd()));
	        			wSubAlgorithm.OnData(data);
	        			wAllAlgosCommunicatedDesiredAllocation &= wSubAlgorithm.CommunicatedDesiredAllocation;
	        		}
	        	}
	        	
	        	// Process the reallocation requests from all sub-algorithms, if all algos ran at least once and gave their required symbols
        		if (wAllAlgosCommunicatedDesiredAllocation) ProcessReallocations(data);
        	}
			
			// If there is more than 1000 USD worth of CAD, convert it to USD
            ConvertCadToUsd();
        }
        
        private decimal GetUnconvertedCadValueInCad()
        {
        	Cash wUnconvertedCAD;
			Portfolio.CashBook.TryGetValue("CAD",out wUnconvertedCAD);
			return wUnconvertedCAD.Amount;
        }
        
        private decimal GetUnconvertedCadValueInUsd()
        {
        	Cash wUnconvertedCAD;
			Portfolio.CashBook.TryGetValue("CAD",out wUnconvertedCAD);
			return wUnconvertedCAD.ValueInAccountCurrency;
        }
        
        private void ConvertCadToUsd()
        {
			decimal wUnconvertedCADValueInUSD = GetUnconvertedCadValueInUsd();
			
			if (wUnconvertedCADValueInUSD >= 1000)
			{
				decimal wHowManyUSDToBuy = Math.Floor(wUnconvertedCADValueInUSD/1000)*1000;
				Log("Converting CAD to USD: Buying " + wHowManyUSDToBuy + " USD");	
				MarketOrder("USDCAD", wHowManyUSDToBuy);
			}
        }
        
        public SharpeRatioCalculator SRC(List<decimal> iSymbolsRatios, int period, decimal volatilityFactor)
        {
            var src = new SharpeRatioCalculator(iSymbolsRatios, period, volatilityFactor);
            return src;
        }
        
        public SharpeRatioCalculator SRC(int period, decimal volatilityFactor)
        {
            var src = new SharpeRatioCalculator(period, volatilityFactor);
            return src;
        }
        
        private void ProcessReallocations(TradeBars data)
        {
        	Dictionary<string,int> wDesiredEquityAmounts = new Dictionary<string,int>();
        	
        	foreach (KeyValuePair<Symbol,Security> wSymbolSecurity in Securities)
        	{
        		if (wSymbolSecurity.Key == "USDCAD") continue;
        		wDesiredEquityAmounts.Add(wSymbolSecurity.Key,0);
        	}

            foreach (SubAlgorithm wSubAlgorithm in mSubAlgorithms)
        	{
                foreach (KeyValuePair<string,int> wSymbolAmount in wSubAlgorithm.mDesiredEquityAmounts)
        		{
        			if (!wDesiredEquityAmounts.ContainsKey(wSymbolAmount.Key))
        			{
        				wDesiredEquityAmounts.Add(wSymbolAmount.Key, 0);
        			}
        			wDesiredEquityAmounts[wSymbolAmount.Key] = wDesiredEquityAmounts[wSymbolAmount.Key] + wSymbolAmount.Value;
        		}
        	}
        	
        	SetHoldingsSellFirst(data, wDesiredEquityAmounts);        	
        }
        
        private void SetHoldingsSellFirst(TradeBars data, Dictionary<string,int> wSymbolsAndAmounts)
        {
        	Dictionary<string,int> wTransactions = new Dictionary<string,int>();
        	
        	int wDesiredAmount = 0;
        	int wActualAmount = 0;
        	int wDelta = 0;
        	foreach (KeyValuePair<string,int> wSymbolAndAmount in wSymbolsAndAmounts)
        	{
        		wDesiredAmount = wSymbolAndAmount.Value;
        		wActualAmount = (int)Securities[wSymbolAndAmount.Key].Holdings.Quantity;
        		wDelta = wDesiredAmount - wActualAmount;
        		
        		if (wDelta != 0 && data.ContainsKey(wSymbolAndAmount.Key))
        		{
        			if ((Math.Abs(wDelta) * data[wSymbolAndAmount.Key].Close) > mAvoidRebalancesBelowThisAmount)
	        		{
	        			wTransactions.Add(wSymbolAndAmount.Key, wDelta);
	        		}
        		}
        	}
        	
        	foreach (KeyValuePair<string,int> wTransaction in wTransactions)
        	{
        		if (wTransaction.Value < 0)
        		{
        			MarketOrder(wTransaction.Key, wTransaction.Value);
        		}
        	}
        	
        	foreach (KeyValuePair<string,int> wTransaction in wTransactions)
        	{
        		if (wTransaction.Value > 0)
        		{
        			MarketOrder(wTransaction.Key, wTransaction.Value);
        		}
        	}
        }
        
        // Helper function to get week of year
		public int GetIso8601WeekOfYear(DateTime time)
		{
		    // Seriously cheat.  If its Monday, Tuesday or Wednesday, then it'll 
		    // be the same week# as whatever Thursday, Friday or Saturday are,
		    // and we always get those right
		    DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
		    if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
		    {
		        time = time.AddDays(3);
		    }
		
		    // Return the week of our adjusted day
		    return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
		}
    }
}
using QuantConnect.Data.Market;

namespace QuantConnect
{
    /// <summary>
    /// 
    /// Empty algorithm. To be used to run live to only monitor IB account without trading.
	/// 
    /// </summary>
    public class EMPTYALGO : SubAlgorithm
    {
		public EMPTYALGO(PortfolioOfStrategies iAlgorithm, Resolution iResolution, decimal iAllocationRatio, int iStartYear, bool iRebalanceOnLaunch) : base(iAlgorithm, iResolution, iAllocationRatio, iStartYear, iRebalanceOnLaunch)
		{
			mDataFeedFrequency = "Weekly";
			mRebalanceFrequency = "Weekly";
			mName = "EMPTYALGO";
		}
		
        public override void Initialize_Specific()
        {

        }
        

        public override void OnData_Specific(TradeBars data)
        {
            mCommunicatedDesiredAllocation = true;
        }
        
        protected override bool IsDataValid(TradeBars iData)
        {
            return true;
        }
    }
}
using System.Net;
using System.Text.RegularExpressions;
using System;
using System.Collections;
using QuantConnect.Data.Market;
using System.Collections.Generic;
using QuantConnect.Securities;
using QuantConnect.Orders;
using System.Globalization;
using System.Linq;

namespace QuantConnect
{
    /// <summary>
    /// 
    /// Universal Investment Strategy (UIS) as described here: http://seekingalpha.com/article/2714185-the-spy-tlt-universal-investment-strategy
    ///
    /// </summary>
    public abstract class SubAlgorithm
    {
    	// Strategy parameters
        protected bool EnableLogs = 				false;
        protected string mDataFeedFrequency = 		"Daily"; // Minute, Hour, Daily, Weekly, Monthly. If shorter than algo resolution, resolution will be used.
        protected string mRebalanceFrequency = 		"Daily"; // Must be a longer timeframe, or equal, to mDataFeedFrequency
        
        private bool mRebalanceOnLaunch = true;
        protected decimal mLastAllocationAmount;
        protected bool mFirstPass = true;
        public decimal mAllocationRatio = 0.0m;
        protected decimal mAllocationAmount = 0.0m;
        protected DateTime mPrevious;
        protected PortfolioOfStrategies mAlgorithm;
        protected Resolution mResolution;
        protected int mStartYear;
        protected bool mKeepFeedingData = false; // If, for some reason, a sub-algorithm needs to keep receiving data (more than just once a day/week/month), toggle this to true.
        public Dictionary<string,int> mDesiredEquityAmounts;
        protected Dictionary<DateTime,Dictionary<string,string>> mHistoryDictionary;
        protected string mName = "";
        protected bool mCommunicatedDesiredAllocation = false;
        protected DateTime Time
		{
		    get
		    {
		        return this.mAlgorithm.Time;
		    }
		}
		protected SecurityManager Securities
		{
		    get
		    {
		        return this.mAlgorithm.Securities;
		    }
		}
		public bool RanOnce
		{
		    get
		    {
		        return !mFirstPass;
		    }
		}
        public bool CommunicatedDesiredAllocation
        {
            get
            {
                return mCommunicatedDesiredAllocation;
            }
        }
        public string Name
		{
		    get
		    {
		        return mName;
		    }
		}
		protected bool LiveMode
		{
		    get
		    {
		        return this.mAlgorithm.LiveMode;
		    }
		}
		public bool RebalanceOnLaunch
		{
		    get
		    {
		        return this.mRebalanceOnLaunch;
		    }
		}
		
        
        public SubAlgorithm(PortfolioOfStrategies iAlgorithm, Resolution iResolution, decimal iAllocationRatio, int iStartYear, bool iRebalanceOnLaunch)
        {
        	mAlgorithm = iAlgorithm;
        	mResolution = iResolution;
        	mAllocationRatio = iAllocationRatio;
        	mStartYear = iStartYear;
        	mRebalanceOnLaunch = iRebalanceOnLaunch;
        	mDesiredEquityAmounts = new Dictionary<string,int>();
        	mHistoryDictionary = new Dictionary<DateTime,Dictionary<string,string>>();
        }

        public void Initialize(decimal iAllocationAmount)
        {
        	mAllocationAmount = iAllocationAmount;
	        mLastAllocationAmount = mAllocationAmount;
	        mDesiredEquityAmounts = new Dictionary<string,int>();
	        Initialize_Specific();
        }
        
        abstract public void Initialize_Specific();
        
        public void SetAllocationAmount(decimal iAllocationAmount)
        {
        	mAllocationAmount = iAllocationAmount;
        }

        public void OnData(TradeBars data)
        {
        	if (!IsDataValid(data)) return;

        	if (!mKeepFeedingData) // If the algo requested to keep feeding data more frequently, do so.
        	{
            	if (mDataFeedFrequency == "Minute")
				{
					// Only once per minute
					if ((mPrevious.Minute == mAlgorithm.Time.Minute) && (mPrevious.Hour == mAlgorithm.Time.Hour) && (mPrevious.Date == mAlgorithm.Time.Date)) return;
				}
				else if (mDataFeedFrequency == "Hour" || mDataFeedFrequency == "Hourly")
				{
					// Only once per hour
					if ((mPrevious.Hour == mAlgorithm.Time.Hour) && (mPrevious.Date == mAlgorithm.Time.Date)) return;
				}
				else if (mDataFeedFrequency == "Daily")
				{
					// Only once per day
					if (mPrevious.Date == mAlgorithm.Time.Date) return; 
				}
				else if (mDataFeedFrequency == "Weekly")
				{
					// only once per week
					if ((GetIso8601WeekOfYear(mPrevious) == GetIso8601WeekOfYear(mAlgorithm.Time)) && (mPrevious.Year == mAlgorithm.Time.Year)) return; // Added year check, because at start of algo, month = Jan 1997, so if we start in jan 2010 for example, the first month used to be skipped.            
				}
				else
				{
					// only once per month
	            	if ((mPrevious.Month == mAlgorithm.Time.Month) && (mPrevious.Year == mAlgorithm.Time.Year)) return; // Added year check, because at start of algo, month = Jan 1997, so if we start in jan 2010 for example, the first month used to be skipped.
				}
        	}
            
            // Dispatch the algorithm
			OnData_Specific(data);
			
            mPrevious = mAlgorithm.Time;
            mLastAllocationAmount = mAllocationAmount;
            mFirstPass = false;
        }
        
        abstract public void OnData_Specific(TradeBars data);
        
        // Helper function to get week of year
		public int GetIso8601WeekOfYear(DateTime time)
		{
		    // Seriously cheat.  If its Monday, Tuesday or Wednesday, then it'll 
		    // be the same week# as whatever Thursday, Friday or Saturday are,
		    // and we always get those right
		    DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
		    if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
		    {
		        time = time.AddDays(3);
		    }
		
		    // Return the week of our adjusted day
		    return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
		}
		
		// Helper function to initialize a SharpeRatioCalculator indicator
		public SharpeRatioCalculator SRC(List<decimal> iSymbolsRatios, int period, decimal volatilityFactor)
        {
            var src = new SharpeRatioCalculator(iSymbolsRatios, period, volatilityFactor);
            return src;
        }
        
        public SharpeRatioCalculator SRC(int period, decimal volatilityFactor)
        {
            var src = new SharpeRatioCalculator(period, volatilityFactor);
            return src;
        }
        
        protected void Reallocate(TradeBars data, List<KeyValuePair<string,decimal>> wSymbolsAndRatios)
        {
        	mDesiredEquityAmounts = new Dictionary<string,int>();
        	
        	foreach (KeyValuePair<string,decimal> wSymbolAndRatio in wSymbolsAndRatios)
        	{
        		mDesiredEquityAmounts.Add(wSymbolAndRatio.Key, (int)(wSymbolAndRatio.Value * mAllocationAmount / data[wSymbolAndRatio.Key].Close));
        	}
            mCommunicatedDesiredAllocation = true;
        }
        
        protected abstract bool IsDataValid(TradeBars iData);
        
        protected bool IsTimeToRebalance()
        {
        	if (!mRebalanceOnLaunch && mFirstPass)
        	{
        		return false;
        	}
        	else if (mRebalanceFrequency == "Daily")
			{
				// Only once per day
				return (mPrevious.Date != mAlgorithm.Time.Date); 
			}
			else if (mRebalanceFrequency == "Weekly")
			{
				// only once per week
				return ((GetIso8601WeekOfYear(mPrevious) != GetIso8601WeekOfYear(mAlgorithm.Time)) || (mPrevious.Year != mAlgorithm.Time.Year)); // Added year check, because at start of algo, month = Jan 1997, so if we start in jan 2010 for example, the first month used to be skipped.
			}
			else
			{
				// only once per month
            	return ((mPrevious.Month != mAlgorithm.Time.Month) || (mPrevious.Year != mAlgorithm.Time.Year)); // Added year check, because at start of algo, month = Jan 1997, so if we start in jan 2010 for example, the first month used to be skipped.
			}
        }
        
        protected void ReadHistoryFromLogicalInvest(string iStrategyPrefix, string iHistoryURL)
        {
			WebClient wc = new System.Net.WebClient();
			byte[] raw = null;
			string webData = "";
			
			try
			{
				raw = wc.DownloadData(iHistoryURL);
			}
			catch
			{
				Log("Could not retrieve " + mName + " history from Logical Invest, at " + iHistoryURL);
				return;
			}
			
			if (raw == null)
			{
				Log("Data retrieved from " + iHistoryURL + " is null.");
				return;
			}

			webData = System.Text.Encoding.UTF8.GetString(raw).Replace("</td><td>",",").Replace("<tr><td>","").Replace("</td></tr>","");
			
			var lines = webData.Split(new[] { Environment.NewLine },StringSplitOptions.None);
			
			DateTime wPreviousDate = new DateTime();
			DateTime wDate = new DateTime();
			int wValuesCounter = 1;
			string wSymbol = "";
			string wRatio = "";
			
			foreach (string line in lines)
			{
				Dictionary<string,string> wEntry = new Dictionary<string,string>();
				
				if(line.Contains("table")) continue;
				if(line.Contains("###")) continue;

				List<string> values = line.Split(',').ToList();
				if (values.Count < 4) continue;
				if (values[0] == "") continue;
				
				wDate = DateTime.Parse(values[1]);
				wDate = new DateTime(wDate.Year, wDate.Month, 1);
				
				if (wDate != wPreviousDate)
				{
					wValuesCounter = 1;
					mHistoryDictionary.Add(wDate,new Dictionary<string,string>());
					wPreviousDate = wDate;
				}
				
            	wSymbol = values[2];
            	wRatio = (values[3].ToDecimal()/100).ToString();
            	
            	mHistoryDictionary[wDate].Add(iStrategyPrefix + "_Symbol" + wValuesCounter, wSymbol);
            	mHistoryDictionary[wDate].Add(iStrategyPrefix + "_Symbol" + wValuesCounter + "_Ratio", wRatio);
				
				wValuesCounter += 1;
			}
        }
        
        
        protected void Trade(TradeBars data, List<string> iSymbolsList, List<decimal> iSymbolsRatios)
        {
        	if (iSymbolsList.Count() != iSymbolsRatios.Count()) {Log("Error in " + Name + ", Trade: Symbols list count must match symbols ratios list count. Number of symbols = " + iSymbolsList.Count() + ", number of ratios = " + iSymbolsRatios.Count()); return;}
        	List<KeyValuePair<string,decimal>> wSymbolsAndRatios = new List<KeyValuePair<string,decimal>>();
			for (int i = 0; i < iSymbolsList.Count; i++)
			{
				wSymbolsAndRatios.Add(new KeyValuePair<string, decimal>(iSymbolsList[i], iSymbolsRatios[i]));
			}
			Reallocate(data, wSymbolsAndRatios);
        }
        
        protected void Trade(TradeBars data, string iSymbol1, decimal iSymbol1Ratio)
        {
        	List<string> wSymbolsList = new List<string>();
        	wSymbolsList.Add(iSymbol1);
        	List<decimal> wSymbolRatiosList = new List<decimal>();
        	wSymbolRatiosList.Add(iSymbol1Ratio);
        	
        	Trade(data, wSymbolsList, wSymbolRatiosList);
        }
        
        protected void Trade(TradeBars data, string iSymbol1, decimal iSymbol1Ratio, string iSymbol2, decimal iSymbol2Ratio)
        {
        	List<string> wSymbolsList = new List<string>();
        	wSymbolsList.Add(iSymbol1);
        	wSymbolsList.Add(iSymbol2);
        	List<decimal> wSymbolRatiosList = new List<decimal>();
        	wSymbolRatiosList.Add(iSymbol1Ratio);
        	wSymbolRatiosList.Add(iSymbol2Ratio);
        	
        	Trade(data, wSymbolsList, wSymbolRatiosList);
        }
        
        protected void Trade(TradeBars data, string iSymbol1, decimal iSymbol1Ratio, string iSymbol2, decimal iSymbol2Ratio, string iSymbol3, decimal iSymbol3Ratio)
        {
        	List<string> wSymbolsList = new List<string>();
        	wSymbolsList.Add(iSymbol1);
        	wSymbolsList.Add(iSymbol2);
        	wSymbolsList.Add(iSymbol3);
        	List<decimal> wSymbolRatiosList = new List<decimal>();
        	wSymbolRatiosList.Add(iSymbol1Ratio);
        	wSymbolRatiosList.Add(iSymbol2Ratio);
        	wSymbolRatiosList.Add(iSymbol3Ratio);
        	
        	Trade(data, wSymbolsList, wSymbolRatiosList);
        }
        
        protected void Trade(TradeBars data, string iSymbol1, decimal iSymbol1Ratio, string iSymbol2, decimal iSymbol2Ratio, string iSymbol3, decimal iSymbol3Ratio, string iSymbol4, decimal iSymbol4Ratio)
        {
        	List<string> wSymbolsList = new List<string>();
        	wSymbolsList.Add(iSymbol1);
        	wSymbolsList.Add(iSymbol2);
        	wSymbolsList.Add(iSymbol3);
        	wSymbolsList.Add(iSymbol4);
        	List<decimal> wSymbolRatiosList = new List<decimal>();
        	wSymbolRatiosList.Add(iSymbol1Ratio);
        	wSymbolRatiosList.Add(iSymbol2Ratio);
        	wSymbolRatiosList.Add(iSymbol3Ratio);
        	wSymbolRatiosList.Add(iSymbol4Ratio);
        	
        	Trade(data, wSymbolsList, wSymbolRatiosList);
        }
        
        protected void Trade(TradeBars data, string iSymbol1, decimal iSymbol1Ratio, string iSymbol2, decimal iSymbol2Ratio, string iSymbol3, decimal iSymbol3Ratio, string iSymbol4, decimal iSymbol4Ratio, string iSymbol5, decimal iSymbol5Ratio)
        {
        	List<string> wSymbolsList = new List<string>();
        	wSymbolsList.Add(iSymbol1);
        	wSymbolsList.Add(iSymbol2);
        	wSymbolsList.Add(iSymbol3);
        	wSymbolsList.Add(iSymbol4);
        	wSymbolsList.Add(iSymbol5);
        	List<decimal> wSymbolRatiosList = new List<decimal>();
        	wSymbolRatiosList.Add(iSymbol1Ratio);
        	wSymbolRatiosList.Add(iSymbol2Ratio);
        	wSymbolRatiosList.Add(iSymbol3Ratio);
        	wSymbolRatiosList.Add(iSymbol4Ratio);
        	wSymbolRatiosList.Add(iSymbol5Ratio);
        	
        	Trade(data, wSymbolsList, wSymbolRatiosList);
        }
        
        protected void SetStartDate(int iYear, int iMonth, int iDay)
        {
        	mAlgorithm.mBacktestDatesOverriden = true;
        	mAlgorithm.SetStartDate(iYear, iMonth, iDay);
        }
        
        protected void SetEndDate(DateTime iEndDate)
        {
        	mAlgorithm.mBacktestDatesOverriden = true;
        	mAlgorithm.SetEndDate(iEndDate);
        }
        
        protected void Log(string iString)
        {
        	mAlgorithm.Log(iString);
        }
        
        protected void Log(int iString)
        {
        	mAlgorithm.Log(iString.ToString());
        }
        
        protected void Log(decimal iString)
        {
        	mAlgorithm.Log(iString.ToString());
        }
        
        protected void Log(TradeBars iString)
        {
        	mAlgorithm.Log(iString.ToString());
        }
        
        protected void AddSecurity(SecurityType securityType, string symbol, Resolution resolution, bool fillDataForward, decimal leverage, bool extendedMarketHours)
        {
        	mAlgorithm.AddSecurity(securityType, symbol, resolution, fillDataForward, leverage, extendedMarketHours);
        }
        
        protected void SetHoldings(Symbol symbol, decimal percentage)
        {
        	mAlgorithm.SetHoldings(symbol, percentage);
        }
        
        protected void Plot(string chart, string series, decimal value)
        {
        	mAlgorithm.Plot(chart, series, value);
        }
        
        protected void Plot(string chart, string series, double value)
        {
        	mAlgorithm.Plot(chart, series, value);
        }
        
        protected void Plot(string chart, string series, Int32 value)
        {
        	mAlgorithm.Plot(chart, series, value);
        }
        
        protected void Plot(string chart, string series, Single value)
        {
        	mAlgorithm.Plot(chart, series, value);
        }
        
        protected IEnumerable<TradeBar> History(Symbol symbol,int numberOfBars, Nullable<Resolution> resolution)
        {
        	return mAlgorithm.History(symbol, numberOfBars, resolution);
        }
        
        protected OrderTicket MarketOrder(Symbol symbol, int quantity)
        {
        	return mAlgorithm.MarketOrder(symbol, quantity);
        }
        
        protected OrderTicket MarketOrder(Symbol symbol, decimal quantity)
        {
        	return mAlgorithm.MarketOrder(symbol, quantity);
        }
    }
}
using QuantConnect.Data.Market;
using System;
using System.Collections.Generic;
using System.Linq;

namespace QuantConnect
{
    /// <summary>
    /// 
    /// Same strategy as UIS, but with addition of ZIV, similar to MYRS strategy explained here: https://seekingalpha.com/article/1698412-how-to-build-an-etf-rotation-strategy-with-50-percent-annualized-returns
    ///
    /// Generally outperformed UIS for 2012-2017, a bit more stable
    ///
	/// 		UIS return	UIS Sharpe	UISZIV return	UISZIV Sharpe
	/// 2011	93,10%		1,981		
	/// 2012	14,54%		0,727		36,37%			1,66
	/// 2013	50,17%		1,609		48,60%			1,67
	/// 2014	56,53%		2,395		58,66%			2,59
	/// 2015	-9,64%		-0,11		-2,94%			0,03
	/// 2016	42,29%		1,488		53,84%			1,87
	/// 2017	57,51%		2,898		56,18%			2,83
    ///
    /// </summary>
    public class UISZIV : SubAlgorithm
    {
    	// Strategy parameters
        private string mSymbol1 = 					"SPY";
        private string mSymbol2 = 					"TLT";
        private string mSymbol3 = 					"SPXU";
        private string mSymbol4 = 					"TMV";
        private string mSymbol5 = 					"ZIV";
        private bool mUseShort = 					false;
        private bool mUseCorrelationExit =			true;	// Cash exit when the correlation between UPRU and TMF is positive, for a 1, 2, and 3 months lookback period. Does not exit ZIV positions.
        private int mMinimumRebalancePeriod = 		1;
        private int mSharpeLookback = 				63; // 63
        private decimal mSharpeVolatilityFactor = 	2.8m; // 2.8
        
        private SharpeRatioCalculator mMaxSharpeCombination;
        private CorrelationCalculator mCorrel2Weeks;
        private CorrelationCalculator mCorrel1Month;
        private CorrelationCalculator mCorrel2Month;
        private CorrelationCalculator mCorrel3Month;
        private int mDaysCounter = 0;
        private List<SharpeRatioCalculator> mSrcList;
        private decimal mLastRatio1 = 0;
        private decimal mLastRatio2 = 0;
        private decimal mLastRatio5 = 0;
        bool mCashExit = false;
        bool mCashExit_previous = false;
        bool mBuyBackIn = false;
        DateTime mLastHistoryCallsDate = DateTime.MinValue;
        List<TradeBar> mTradeBarHistorySymbol1;
        List<TradeBar> mTradeBarHistorySymbol2;
        List<TradeBar> mTradeBarHistorySymbol5;


		public UISZIV(PortfolioOfStrategies iAlgorithm, Resolution iResolution, decimal iAllocationRatio, int iStartYear, bool iRebalanceOnLaunch) : base(iAlgorithm, iResolution, iAllocationRatio, iStartYear, iRebalanceOnLaunch)
		{
			if (LiveMode)
			{
				mDataFeedFrequency = "Minute";
			}
			else
			{
				mDataFeedFrequency = "Daily"; // Needs to stay daily or faster, for correlation exits and historical performances calculation
			}
			mRebalanceFrequency = "Weekly";
			mName = "UISZIV";
		}
		
        public override void Initialize_Specific()
        {
        	if (EnableLogs)
        	{
	        	Log("UISZIV Strategy: Backtesting with following parameters:");
	        	Log("\tSymbol1                    >> " + mSymbol1);
		        Log("\tSymbol2                    >> " + mSymbol2);
		        if (mUseShort)
		        {
		        	Log("\tSymbol3                    >> " + mSymbol3);
		        	Log("\tSymbol4                    >> " + mSymbol4);
		        }
		        Log("\tUseShort                   >> " + mUseShort);
		        Log("\tMinimum Rebalance Period   >> " + mMinimumRebalancePeriod);
		        Log("\tStart year                 >> " + mStartYear);
		        Log("\tSharpe lookback            >> " + mSharpeLookback);
		        Log("\tSharpe volatility factor   >> " + mSharpeVolatilityFactor);
        	}
	        
            AddSecurity(SecurityType.Equity, mSymbol1, mResolution, true, 3, false);
            AddSecurity(SecurityType.Equity, mSymbol2, mResolution, true, 3, false);
            AddSecurity(SecurityType.Equity, mSymbol5, mResolution, true, 3, false);
			if (mUseShort)
	        {
	        	AddSecurity(SecurityType.Equity, mSymbol3, mResolution, true, 3, false);
            	AddSecurity(SecurityType.Equity, mSymbol4, mResolution, true, 3, false);
	        }
            mTradeBarHistorySymbol1 = new List<TradeBar>();
            mTradeBarHistorySymbol2 = new List<TradeBar>();
            mTradeBarHistorySymbol5 = new List<TradeBar>();

            RecalculateSharpeRatios(mSharpeLookback, mSharpeVolatilityFactor, ref mSrcList);
        }

        public override void OnData_Specific(TradeBars data)
        {
            mDaysCounter = mDaysCounter - 1;
            
            RecalculateSharpeRatios(mSharpeLookback, mSharpeVolatilityFactor, ref mSrcList);
            
            // For backtesting purposes only, exclude the discontinuity that occured in the data on Aug 22-25 2016
            if (Time.Date >= DateTime.Parse("08/22/2016") && Time.Date <= DateTime.Parse("08/26/2016"))
            {
            	if (mUseShort)
        		{
	                Trade(data, mSymbol3, 0, mSymbol4, 0, mSymbol5, 0);
        		}
        		else
        		{
        			Trade(data, mSymbol1, 0, mSymbol2, 0, mSymbol5, 0);
        		}
            	return;
            }
            
            decimal wRatio1 = 0.0m;
            decimal wRatio2 = 0.0m;
            decimal wRatio5 = 0.0m;
            if (mSrcList[0].IsReady)
            {
            	mMaxSharpeCombination = mSrcList.Select( (value, index) => new { Value = value, Index = index } ).Aggregate( (a, b) => (a.Value > b.Value) ? a : b ).Value;
            	wRatio1 = mMaxSharpeCombination.mSymbolsRatios[0];
            	wRatio2 = mMaxSharpeCombination.mSymbolsRatios[1];
            	wRatio5 = mMaxSharpeCombination.mSymbolsRatios[2];
            }

            if (mFirstPass == true || mDaysCounter <= 0 || mLastRatio1 != wRatio1 || mLastRatio2 != wRatio2 || mLastRatio5 != wRatio5)
            {
            	mDaysCounter = mMinimumRebalancePeriod;
            	
            	if (EnableLogs)
            	{
            		Log(" ");
	            	Log("Rebalancing:");
            	}
            	
	            if (mSrcList[0].IsReady)
	            {
	            	mMaxSharpeCombination = mSrcList.Select( (value, index) => new { Value = value, Index = index } ).Aggregate( (a, b) => (a.Value > b.Value) ? a : b ).Value;
					
					if (EnableLogs)
	            	{
		                Log("     Max Sharpe Combination >> " + mSymbol1 + " " + (mMaxSharpeCombination.mSymbolsRatios[0] * 100).ToString ("#.#") + "%,  " + mSymbol2 + " " + (mMaxSharpeCombination.mSymbolsRatios[1] * 100).ToString ("#.#") + "%.");
	            	}
	            	
	            	decimal wSymbol1Ratio = mMaxSharpeCombination.mSymbolsRatios[0];
        			decimal wSymbol2Ratio = mMaxSharpeCombination.mSymbolsRatios[1];
					decimal wSymbol5Ratio = mMaxSharpeCombination.mSymbolsRatios[2];
					
					if (mUseCorrelationExit)
					{
						// Cash exit when the correlation between UPRU and TMF is positive, for a 1, 2, and 3 months lookback period. Does not exit ZIV positions.
						if (mCorrel1Month.Correlation > 0 && mCorrel2Month.Correlation > 0 && mCorrel3Month.Correlation > 0)
	            		{
	            			wSymbol1Ratio = 0;
	            			wSymbol2Ratio = 0;
	            			mCashExit = true;
	            			
	            			if (EnableLogs)
			            	{
			            		Log("Cash exit: Correlation between UPRO and TMF is positive for 1, 2, and 3 months lookback period. Keeping ZIV positions.");
			            	}
	            		}
	            		else if (mCashExit == true && mBuyBackIn == false)
	            		{
	            			mCashExit = false;
	            			mBuyBackIn = true;
	            		}
					}
					
					// Trade if it it time to trade, or if there is cash exit toggle or buy back in toggle
	            	if ((mCashExit && !mCashExit_previous) || mBuyBackIn || IsTimeToRebalance())
					{
						if (mUseShort)
	            		{
			                Trade(data, mSymbol3, -wSymbol1Ratio, mSymbol4, -wSymbol2Ratio, mSymbol5, wSymbol5Ratio);
	            		}
	            		else
	            		{
	            			Trade(data, mSymbol1, wSymbol1Ratio, mSymbol2, wSymbol2Ratio, mSymbol5, wSymbol5Ratio);
	            		}
	            		
	            		mBuyBackIn = false;
					}
	                mCashExit_previous = mCashExit;
	            }
	            else
	            {
		            if (EnableLogs) Log("     Sharpe not ready       >> " + mSymbol1 + " 50%,  " + mSymbol2 + " 50%.");
	                
	                if (IsTimeToRebalance())
					{
		            	// If sharpe ratio not ready yet, use a 50%-50% split between UPRO and TMF
	                	if (mUseShort)
	            		{
			                Trade(data, mSymbol3, -0.5m, mSymbol4, -0.5m, mSymbol5, 0.0m);
	            		}
	            		else
	            		{
	            			Trade(data, mSymbol1, 0.5m, mSymbol2, 0.5m, mSymbol5, 0.0m);
	            		}
					}
	            }
	            
	            
	            mLastAllocationAmount = mAllocationAmount;
	            mLastRatio1 = wRatio1;
	            mLastRatio2 = wRatio2;
	            mLastRatio5 = wRatio5;
            }

            decimal wSymbol1Percentage;
            decimal wSymbol2Percentage;
            decimal wSymbol5Percentage;
            
            if (mSrcList[0].IsReady && mMaxSharpeCombination != null)
            {
            	wSymbol1Percentage = mMaxSharpeCombination.mSymbolsRatios[0] * 100;
            	wSymbol2Percentage = mMaxSharpeCombination.mSymbolsRatios[1] * 100;
            	wSymbol5Percentage = mMaxSharpeCombination.mSymbolsRatios[2] * 100;
            }
            else
            {
            	wSymbol1Percentage = 50;
            	wSymbol2Percentage = 50;
            	wSymbol5Percentage = 0;
            }
			
            Plot(mSymbol1 + "-" + mSymbol2 + "-" + mSymbol5 + " Split", mSymbol1 + " (%)", wSymbol1Percentage);
            Plot(mSymbol1 + "-" + mSymbol2 + "-" + mSymbol5 + " Split", mSymbol2 + " (%)", wSymbol2Percentage);
            Plot(mSymbol1 + "-" + mSymbol2 + "-" + mSymbol5 + " Split", mSymbol5 + " (%)", wSymbol5Percentage);
            Plot(mSymbol1 + "-" + mSymbol2 + " Correlation", "Correl 2 Weeks", mCorrel2Weeks.Correlation*100);
            Plot(mSymbol1 + "-" + mSymbol2 + " Correlation", "Correl 1 Month", mCorrel1Month.Correlation*100);
            Plot(mSymbol1 + "-" + mSymbol2 + " Correlation", "Correl 2 Months", mCorrel2Month.Correlation*100);
            Plot(mSymbol1 + "-" + mSymbol2 + " Correlation", "Correl 3 Months", mCorrel3Month.Correlation*100);
            Plot(mSymbol1 + "-" + mSymbol2 + " Correlation", "0", 0);
        }
        
        protected override bool IsDataValid(TradeBars iData)
        {
        	bool wValid = true;
            
            if (!mUseShort)
            {
            	wValid &= iData.ContainsKey(mSymbol1);
            	wValid &= iData.ContainsKey(mSymbol2);
				wValid &= iData.ContainsKey(mSymbol5);
            }
            if (mUseShort)
            {
            	wValid &= iData.ContainsKey(mSymbol3);
            	wValid &= iData.ContainsKey(mSymbol4);
				wValid &= iData.ContainsKey(mSymbol5);
            }
            return wValid;
        }
        
        private void RecalculateSharpeRatios(int iLookback, decimal iVolatilityFactor, ref List<SharpeRatioCalculator> iSrcList)
        {
            iSrcList = new List<SharpeRatioCalculator>();
            mCorrel2Weeks = new CorrelationCalculator(10);
            mCorrel1Month = new CorrelationCalculator(21);
            mCorrel2Month = new CorrelationCalculator(42);
            mCorrel3Month = new CorrelationCalculator(63);
			
        	int granularity = 10;
            for (decimal i = 0.0m; i <= 1.0m; i+=(decimal)(1.0m/granularity))
	        {
	        	for (decimal j = 0.0m; j <= 1.0m-i; j+=(decimal)(1.0m/granularity))
		        {
			        	List<decimal> wSymbolsRatios = new List<decimal>();
			        	wSymbolsRatios.Add(j);
			        	wSymbolsRatios.Add(1.0m-i-j);
			        	wSymbolsRatios.Add(i);
			        	iSrcList.Add(SRC(wSymbolsRatios, iLookback, iVolatilityFactor));
		        }
	        }
	        
            // get the last 100 daily bars, once a day
            if (mAlgorithm.Time.Date > mLastHistoryCallsDate.Date)
            {
                mLastHistoryCallsDate = mAlgorithm.Time;
                mTradeBarHistorySymbol1 = History(mSymbol1, 100, Resolution.Daily).ToList();
                mTradeBarHistorySymbol2 = History(mSymbol2, 100, Resolution.Daily).ToList();
                mTradeBarHistorySymbol5 = History(mSymbol5, 100, Resolution.Daily).ToList();
            }

            for (int i = 0; i < mTradeBarHistorySymbol5.Count(); i++)
            {
            	for (int j = 0; j < iSrcList.Count; j++)
		        {
		        	List<TradeBar> wData = new List<TradeBar>();
		        	wData.Add(mTradeBarHistorySymbol1[i]);
		        	wData.Add(mTradeBarHistorySymbol2[i]);
		        	wData.Add(mTradeBarHistorySymbol5[i]);
		            iSrcList[j].AddObservation(wData);
		        }
		        mCorrel2Weeks.AddObservation((double)mTradeBarHistorySymbol1[i].Close, (double)mTradeBarHistorySymbol2[i].Close);
		        mCorrel1Month.AddObservation((double)mTradeBarHistorySymbol1[i].Close, (double)mTradeBarHistorySymbol2[i].Close);
		        mCorrel2Month.AddObservation((double)mTradeBarHistorySymbol1[i].Close, (double)mTradeBarHistorySymbol2[i].Close);
		        mCorrel3Month.AddObservation((double)mTradeBarHistorySymbol1[i].Close, (double)mTradeBarHistorySymbol2[i].Close);
		    }
        }
        
    }
}
using QuantConnect.Data.Market;
using QuantConnect.Util;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace QuantConnect
{
    /// <summary>
    /// 
    /// Bond rotation strategy (BRS) as described here: https://seekingalpha.com/article/2936206-the-new-enhanced-bond-rotation-strategy-with-adaptive-bond-allocation
    ///
    /// Optimization results:
    /// lookback	volatilityfactor	CAGR	Sharpe
	/// 40			1.5					10.32	1.407
	/// 50			1.5					10.07	1.365
	/// 60			1.5					9.595	1.302
	/// 70			1.5					10.41	1.402
	/// 80			1.5					9.214	1.225
	/// 40			1.75				10.508	1.453
	/// 50			1.75				10.356	1.437
	/// 60			1.75				9.335	1.278
	/// 70			1.75				10.499	1.422
	/// 80			1.75				9.634	1.291
	/// 40			2					10.417	1.443
	/// 50			2					10.203	1.428
	/// 60			2					9.528	1.311
	/// 70			2					10.295	1.403
	/// 80			2					9.835	1.326
	/// 40			2.25				10.155	1.422
	/// 50			2.25				10.956	1.53
	/// 60			2.25				9.362	1.296
	/// 70			2.25				9.674	1.367
	/// 80			2.25				9.024	1.25
	/// 40			2.5					10.284	1.449
	/// 50			2.5					10.941	1.536
	/// 60			2.5					9.388	1.305
	/// 70			2.5					9.478	1.35
	/// 80			2.5					8.98	1.261
	/// 40			2.75				10.055	1.457
	/// 50			2.75				10.987	1.545
	/// 60			2.75				9.492	1.319
	/// 70			2.75				9.492	1.353
	/// 80			2.75				9.263	1.306
	/// 40			3		
	/// 50			3					11.225	1.583
	/// 
    /// </summary>
    public class BRS : SubAlgorithm
    {
    	// Strategy parameters
        private string mSymbol1 = 					"CWB";
        private string mSymbol2 = 					"JNK";
        private string mSymbol3 = 					"TLT";
        private string mSymbol4 = 					"PCY";
        private int mMinimumRebalancePeriod = 		1;
        private int mSharpeLookback = 				50; //50
        private decimal mSharpeVolatilityFactor = 	3.0m; //3.0
        private decimal SharpeThresholdForCash =	0; // Threshold for max sharpe ratio under which the algo will go 50% cash. Needs to be tuned when changes to volatility factor are made.
        
        private SharpeRatioCalculator mMaxSharpeCombination;
        private int mDaysCounter = 0;
        private List<SharpeRatioCalculator> mSrcList;
        private decimal mLastRatio1 = 0;
        private decimal mLastRatio2 = 0;
        private decimal mLastRatio3 = 0;
        private decimal mLastRatio4 = 0;
		
        DateTime mLastHistoryCallsDate = DateTime.MinValue;
        List<TradeBar> mTradeBarHistorySymbol1;
        List<TradeBar> mTradeBarHistorySymbol2;
        List<TradeBar> mTradeBarHistorySymbol3;
        List<TradeBar> mTradeBarHistorySymbol4;
		public BRS(PortfolioOfStrategies iAlgorithm, Resolution iResolution, decimal iAllocationRatio, int iStartYear, bool iRebalanceOnLaunch) : base(iAlgorithm, iResolution, iAllocationRatio, iStartYear, iRebalanceOnLaunch)
		{
			if (LiveMode)
			{
				mDataFeedFrequency = "Minute";
			}
			else
			{
				mDataFeedFrequency = "Monthly";
			}
			mRebalanceFrequency = "Monthly";
			mName = "BRS";
		}
		
        public override void Initialize_Specific()
        {
        	if (EnableLogs)
        	{
	        	Log("BRS Strategy: Backtesting with following parameters:");
	        	Log("\tSymbol1                    >> " + mSymbol1);
		        Log("\tSymbol2                    >> " + mSymbol2);
		        Log("\tSymbol3                    >> " + mSymbol3);
		        Log("\tSymbol4                    >> " + mSymbol4);
		        Log("\tMinimum Rebalance Period   >> " + mMinimumRebalancePeriod);
		        Log("\tStart year                 >> " + mStartYear);
		        Log("\tSharpe lookback            >> " + mSharpeLookback);
		        Log("\tSharpe volatility factor   >> " + mSharpeVolatilityFactor);
        	}
	        
            AddSecurity(SecurityType.Equity, mSymbol1, mResolution, true, 3, false);
            AddSecurity(SecurityType.Equity, mSymbol2, mResolution, true, 3, false);
	        AddSecurity(SecurityType.Equity, mSymbol3, mResolution, true, 3, false);
            AddSecurity(SecurityType.Equity, mSymbol4, mResolution, true, 3, false);
            
            mTradeBarHistorySymbol1 = new List<TradeBar>();
            mTradeBarHistorySymbol2 = new List<TradeBar>();
            mTradeBarHistorySymbol3 = new List<TradeBar>();
			mTradeBarHistorySymbol4 = new List<TradeBar>();
	        
	        RecalculateSharpeRatios(mSharpeLookback, mSharpeVolatilityFactor, ref mSrcList);
        }

        public override void OnData_Specific(TradeBars data)
        {
            mDaysCounter = mDaysCounter - 1;
            
            RecalculateSharpeRatios(mSharpeLookback, mSharpeVolatilityFactor, ref mSrcList);
            
            decimal wRatio1 = 0.0m;
            decimal wRatio2 = 0.0m;
            decimal wRatio3 = 0.0m;
            decimal wRatio4 = 0.0m;
            
            if (mSrcList[0].IsReady)
            {
            	mMaxSharpeCombination = mSrcList.Select( (value, index) => new { Value = value, Index = index } ).Aggregate( (a, b) => (a.Value > b.Value) ? a : b ).Value;
            	// If the maximum sharpe ratio combination yields a sharpe ratio below SharpeThresholdForCash, then reduce ratios by 50% and invest 50% in cash
            	if (mMaxSharpeCombination < SharpeThresholdForCash)
            	{
            		for (int i=0; i<mMaxSharpeCombination.mSymbolsRatios.Count(); i++)
            		{
            			mMaxSharpeCombination.mSymbolsRatios[i] = mMaxSharpeCombination.mSymbolsRatios[i] / 2;
            		}
            	}
            	wRatio1 = mMaxSharpeCombination.mSymbolsRatios[0];
            	wRatio2 = mMaxSharpeCombination.mSymbolsRatios[1];
            	wRatio3 = mMaxSharpeCombination.mSymbolsRatios[2];
            	wRatio4 = mMaxSharpeCombination.mSymbolsRatios[3];
            }
			
            if (mFirstPass == true || mDaysCounter <= 0 || mLastRatio1 != wRatio1 || mLastRatio2 != wRatio2 || mLastRatio3 != wRatio3 || mLastRatio4 != wRatio4)
            {
            	mDaysCounter = mMinimumRebalancePeriod;
            	
            	if (EnableLogs)
            	{
            		Log(" ");
	            	Log("Rebalancing:");
            	}
            	
	            if (mSrcList[0].IsReady)
	            {
	            	mMaxSharpeCombination = mSrcList.Select( (value, index) => new { Value = value, Index = index } ).Aggregate( (a, b) => (a.Value > b.Value) ? a : b ).Value;
					
	                if (EnableLogs) Log("     Max Sharpe Combination >> " +
		                mSymbol1 + " " + (mMaxSharpeCombination.mSymbolsRatios[0] * 100).ToString ("#.#") + "%,  " + 
		                mSymbol2 + " " + (mMaxSharpeCombination.mSymbolsRatios[1] * 100).ToString ("#.#") + "%,  " +
		                mSymbol3 + " " + (mMaxSharpeCombination.mSymbolsRatios[2] * 100).ToString ("#.#") + "%,  " +
		                mSymbol4 + " " + (mMaxSharpeCombination.mSymbolsRatios[3] * 100).ToString ("#.#") + "%.");
					
					if (IsTimeToRebalance())
					{
						Trade(data, 
	            			mSymbol1, mMaxSharpeCombination.mSymbolsRatios[0], 
	            			mSymbol2, mMaxSharpeCombination.mSymbolsRatios[1], 
	            			mSymbol3, mMaxSharpeCombination.mSymbolsRatios[2], 
	            			mSymbol4, mMaxSharpeCombination.mSymbolsRatios[3]);
					}
            		
	            }
	            else
	            {
	            	if (EnableLogs) Log("     Sharpe not ready       >> " + 
	            		mSymbol1 + " 50%,  " + 
	            		mSymbol2 + " 50%,  " + 
	            		mSymbol3 + " 0%,  " + 
	            		mSymbol4 + " 0%.");
	                
	                if (IsTimeToRebalance())
					{
		            	// If sharpe ratio not ready yet, use a 50%-50% split
	            		Trade(data, 
	            			mSymbol1, 0.5m, 
	            			mSymbol2, 0.5m, 
	            			mSymbol3, 0.0m, 
	            			mSymbol4, 0.0m);
					}
	            }
	            
	            mLastAllocationAmount = mAllocationAmount;
	            mLastRatio1 = wRatio1;
            }

            decimal wSymbol1Percentage;
            decimal wSymbol2Percentage;
            decimal wSymbol3Percentage;
            decimal wSymbol4Percentage;
            
            if (mSrcList[0].IsReady && mMaxSharpeCombination != null)
            {
            	wSymbol1Percentage = mMaxSharpeCombination.mSymbolsRatios[0] * 100;
            	wSymbol2Percentage = mMaxSharpeCombination.mSymbolsRatios[1] * 100;
            	wSymbol3Percentage = mMaxSharpeCombination.mSymbolsRatios[2] * 100;
            	wSymbol4Percentage = mMaxSharpeCombination.mSymbolsRatios[3] * 100;
            }
            else
            {
            	wSymbol1Percentage = 50;
            	wSymbol2Percentage = 50;
            	wSymbol3Percentage = 0;
            	wSymbol4Percentage = 0;
            }

            Plot("BRS Assets Split", mSymbol1 + " (%)", wSymbol1Percentage);
            Plot("BRS Assets Split", mSymbol2 + " (%)", wSymbol2Percentage);
            Plot("BRS Assets Split", mSymbol3 + " (%)", wSymbol3Percentage);
            Plot("BRS Assets Split", mSymbol4 + " (%)", wSymbol4Percentage);
        }
        
        protected override bool IsDataValid(TradeBars iData)
        {
        	bool wValid = true;
        	
        	wValid &= iData.ContainsKey(mSymbol1);
        	wValid &= iData.ContainsKey(mSymbol2);
			wValid &= iData.ContainsKey(mSymbol3);
			wValid &= iData.ContainsKey(mSymbol4);
			
            return wValid;
        }
        
        private void RecalculateSharpeRatios(int iLookback, decimal iVolatilityFactor, ref List<SharpeRatioCalculator> iSrcList)
        {
        	iSrcList = new List<SharpeRatioCalculator>();
	        
	        for (int i=0; i<4; i++)
	        {
	        	for (int j=i+1; j<4; j++)
	        	{
	        		for (decimal k=0.4m; k<=0.6m; k+=0.05m)
	        		{
	        			List<decimal> wSymbolsRatios = new List<decimal> {0.0m,0.0m,0.0m,0.0m};
	        			wSymbolsRatios[i] = k;
	        			wSymbolsRatios[j] = 1-k;
	        			iSrcList.Add(SRC(wSymbolsRatios,iLookback,iVolatilityFactor));
	        		}
	        	}
	        }

	        // get the last 100 daily bars, once a day
            if (mAlgorithm.Time.Date > mLastHistoryCallsDate.Date)
            {
                mLastHistoryCallsDate = mAlgorithm.Time;
                mTradeBarHistorySymbol1 = History(mSymbol1, 100, Resolution.Daily).ToList();
                mTradeBarHistorySymbol2 = History(mSymbol2, 100, Resolution.Daily).ToList();
                mTradeBarHistorySymbol3 = History(mSymbol3, 100, Resolution.Daily).ToList();
				mTradeBarHistorySymbol4 = History(mSymbol4, 100, Resolution.Daily).ToList();
            }

            for (int i = 0; i < mTradeBarHistorySymbol1.Count(); i++)
            {
            	for (int j = 0; j < iSrcList.Count; j++)
		        {
		        	List<TradeBar> wData = new List<TradeBar>();
		        	wData.Add(mTradeBarHistorySymbol1[i]);
		        	wData.Add(mTradeBarHistorySymbol2[i]);
		        	wData.Add(mTradeBarHistorySymbol3[i]);
		        	wData.Add(mTradeBarHistorySymbol4[i]);
		            iSrcList[j].AddObservation(wData);
		        }
            }
        }
    }
}
namespace QuantConnect {

    public class SharpeRatioCalculator
	{
	    
	    public SharpeRatioCalculator(List<decimal> iSymbolsRatios, int period, decimal volatilityFactor)
	    {
			mSymbolsRatios = iSymbolsRatios;
			mVolatilityFactor = volatilityFactor;
			mPreviousTradeBars = new List<TradeBar>();
			for (int i = 0; i<iSymbolsRatios.Count(); i++)
			{
				mPreviousTradeBars.Add(null);
			}
			SharpeRatio = 0.0m;
	        MAC = new MovingAverageCalculator(period);
	    }
	    
	    public SharpeRatioCalculator(int period, decimal volatilityFactor)
	    {
			mSymbolsRatios = new List<decimal>();
			mSymbolsRatios.Add(1.0m);
			mVolatilityFactor = volatilityFactor;
			mPreviousTradeBars = new List<TradeBar>();
			mPreviousTradeBars.Add(null);
			
			SharpeRatio = 0.0m;
	        MAC = new MovingAverageCalculator(period);
	    }
	
	    public double Average 
	    {
	        get { return MAC.Average; }
	    }
	
	    public double StandardDeviation
	    {
	        get { return MAC.StandardDeviation; }
	    }
	
	    public double Variance
	    {
	        get { return MAC.Variance; }
	    }
	
		public bool IsReady
	    {
	        get { return MAC.HasFullPeriod; }
	    }
	    
	    public bool HasFullPeriod
	    {
	        get { return MAC.HasFullPeriod; }
	    }
	
	    public IEnumerable<double> Observations
	    {
	        get { return MAC.Observations; }
	    }
	
	    public int N
	    {
	        get { return MAC.N; }
	    }
	    
	
		public void AddObservation(List<TradeBar> iData)
	    {
	    	for (int i = 0; i < iData.Count; i++)
	    	{
	    		if (mPreviousTradeBars[i] == null) mPreviousTradeBars[i] = iData[i];
	    	}
	    	
	    	List<decimal> wSymbolSplitFactorList = new List<decimal>();
	    	for (int i = 0; i < iData.Count; i++)
	    	{
	    		decimal wSymbolSplitFactor = 1.0m;
	    		if (mPreviousTradeBars[i].Close > iData[i].Close)
	    		{
		    		wSymbolSplitFactor = Math.Round(mPreviousTradeBars[i].Close / iData[i].Close);
		    	}
		    	else
		    	{
		    		wSymbolSplitFactor = 1.0m / Math.Round(iData[i].Close / mPreviousTradeBars[i].Close);
		    	}
		    	wSymbolSplitFactorList.Add(wSymbolSplitFactor);
	    	}
	    	
	    	List<decimal> wDailyReturns = new List<decimal>();
	    	for (int i = 0; i < iData.Count; i++)
	    	{
	    		decimal wDailyReturn = ((iData[i].Close * wSymbolSplitFactorList[i]) - mPreviousTradeBars[i].Close) / mPreviousTradeBars[i].Close;
	    		wDailyReturns.Add(wDailyReturn);
	    	}
			
			decimal wTotalDailyReturn = 0.0m;
			for (int i = 0; i < iData.Count; i++)
	    	{
	    		wTotalDailyReturn = wTotalDailyReturn + (wDailyReturns[i] * mSymbolsRatios[i]);
	    	}
	    	
	        MAC.AddObservation((double) wTotalDailyReturn);
	        
	        if (MAC.HasFullPeriod && MAC.StandardDeviation > 0)
	        {
	        	SharpeRatio = (decimal) (MAC.Average / Math.Pow(MAC.StandardDeviation, (double) mVolatilityFactor));
	        }
	        
	        for (int i = 0; i < iData.Count; i++)
	    	{
	    		mPreviousTradeBars[i] = iData[i];
	    	}
	    }
	    
	    public void AddObservation(List<decimal> iCloseData)
	    {
	    	List<TradeBar> wTradeBarsData = new List<TradeBar>();
	    	
	    	foreach (decimal wCloseData in iCloseData)
	    	{
	    		wTradeBarsData.Add(new TradeBar(new DateTime(),"Portfolio",wCloseData,wCloseData,wCloseData,wCloseData,wCloseData,null));
	    	}
	    	AddObservation(wTradeBarsData);
	    }
	    
	    public void AddObservation(decimal iCloseData)
	    {
	    	List<TradeBar> wTradeBarsData = new List<TradeBar>();
	    	wTradeBarsData.Add(new TradeBar(new DateTime(),"Portfolio",iCloseData,iCloseData,iCloseData,iCloseData,iCloseData,null));
	    	AddObservation(wTradeBarsData);
	    }
	
	    public MovingAverageCalculator MAC;
	    private decimal SharpeRatio;
	    public List<decimal> mSymbolsRatios;
	    public List<TradeBar> mPreviousTradeBars;
	    public decimal mVolatilityFactor;
	    
	    
	    /// <summary>
        /// Returns the current value of this instance
        /// </summary>
        /// <param name="instance">The indicator instance</param>
        /// <returns>The current value of the indicator</returns>
        public static implicit operator decimal(SharpeRatioCalculator instance)
        {
            return instance.SharpeRatio;
        }

        /// <summary>
        /// Determines if the indicator's current value is greater than the specified value
        /// </summary>
        public static bool operator >(SharpeRatioCalculator left, double right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio > (decimal)right;
        }

        /// <summary>
        /// Determines if the indicator's current value is less than the specified value
        /// </summary>
        public static bool operator <(SharpeRatioCalculator left, double right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio < (decimal)right;
        }

        /// <summary>
        /// Determines if the specified value is greater than the indicator's current value
        /// </summary>
        public static bool operator >(double left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return (decimal)left > right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the specified value is less than the indicator's current value
        /// </summary>
        public static bool operator <(double left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return (decimal)left < right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the indicator's current value is greater than or equal to the specified value
        /// </summary>
        public static bool operator >=(SharpeRatioCalculator left, double right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio >= (decimal)right;
        }

        /// <summary>
        /// Determines if the indicator's current value is less than or equal to the specified value
        /// </summary>
        public static bool operator <=(SharpeRatioCalculator left, double right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio <= (decimal)right;
        }

        /// <summary>
        /// Determines if the specified value is greater than or equal to the indicator's current value
        /// </summary>
        public static bool operator >=(double left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return (decimal)left >= right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the specified value is less than or equal to the indicator's current value
        /// </summary>
        public static bool operator <=(double left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return (decimal)left <= right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the indicator's current value is equal to the specified value
        /// </summary>
        public static bool operator ==(SharpeRatioCalculator left, double right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio == (decimal)right;
        }

        /// <summary>
        /// Determines if the indicator's current value is not equal to the specified value
        /// </summary>
        public static bool operator !=(SharpeRatioCalculator left, double right)
        {
            if (ReferenceEquals(left, null)) return true;
            return left.SharpeRatio != (decimal)right;
        }

        /// <summary>
        /// Determines if the specified value is equal to the indicator's current value
        /// </summary>
        public static bool operator ==(double left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return (decimal)left == right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the specified value is not equal to the indicator's current value
        /// </summary>
        public static bool operator !=(double left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return true;
            return (decimal)left != right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the indicator's current value is greater than the specified value
        /// </summary>
        public static bool operator >(SharpeRatioCalculator left, float right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio > (decimal)right;
        }

        /// <summary>
        /// Determines if the indicator's current value is less than the specified value
        /// </summary>
        public static bool operator <(SharpeRatioCalculator left, float right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio < (decimal)right;
        }

        /// <summary>
        /// Determines if the specified value is greater than the indicator's current value
        /// </summary>
        public static bool operator >(float left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return (decimal)left > right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the specified value is less than the indicator's current value
        /// </summary>
        public static bool operator <(float left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return (decimal)left < right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the indicator's current value is greater than or equal to the specified value
        /// </summary>
        public static bool operator >=(SharpeRatioCalculator left, float right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio >= (decimal)right;
        }

        /// <summary>
        /// Determines if the indicator's current value is less than or equal to the specified value
        /// </summary>
        public static bool operator <=(SharpeRatioCalculator left, float right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio <= (decimal)right;
        }

        /// <summary>
        /// Determines if the specified value is greater than or equal to the indicator's current value
        /// </summary>
        public static bool operator >=(float left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return (decimal)left >= right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the specified value is less than or equal to the indicator's current value
        /// </summary>
        public static bool operator <=(float left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return (decimal)left <= right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the indicator's current value is equal to the specified value
        /// </summary>
        public static bool operator ==(SharpeRatioCalculator left, float right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio == (decimal)right;
        }

        /// <summary>
        /// Determines if the indicator's current value is not equal to the specified value
        /// </summary>
        public static bool operator !=(SharpeRatioCalculator left, float right)
        {
            if (ReferenceEquals(left, null)) return true;
            return left.SharpeRatio != (decimal)right;
        }

        /// <summary>
        /// Determines if the specified value is equal to the indicator's current value
        /// </summary>
        public static bool operator ==(float left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return (decimal)left == right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the specified value is not equal to the indicator's current value
        /// </summary>
        public static bool operator !=(float left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return true;
            return (decimal)left != right.SharpeRatio;
        }
        /// <summary>
        /// Determines if the indicator's current value is greater than the specified value
        /// </summary>
        public static bool operator >(SharpeRatioCalculator left, int right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio > right;
        }

        /// <summary>
        /// Determines if the indicator's current value is less than the specified value
        /// </summary>
        public static bool operator <(SharpeRatioCalculator left, int right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio < right;
        }

        /// <summary>
        /// Determines if the specified value is greater than the indicator's current value
        /// </summary>
        public static bool operator >(int left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return left > right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the specified value is less than the indicator's current value
        /// </summary>
        public static bool operator <(int left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return left < right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the indicator's current value is greater than or equal to the specified value
        /// </summary>
        public static bool operator >=(SharpeRatioCalculator left, int right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio >= right;
        }

        /// <summary>
        /// Determines if the indicator's current value is less than or equal to the specified value
        /// </summary>
        public static bool operator <=(SharpeRatioCalculator left, int right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio <= right;
        }

        /// <summary>
        /// Determines if the specified value is greater than or equal to the indicator's current value
        /// </summary>
        public static bool operator >=(int left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return left >= right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the specified value is less than or equal to the indicator's current value
        /// </summary>
        public static bool operator <=(int left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return left <= right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the indicator's current value is equal to the specified value
        /// </summary>
        public static bool operator ==(SharpeRatioCalculator left, int right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio == right;
        }

        /// <summary>
        /// Determines if the indicator's current value is not equal to the specified value
        /// </summary>
        public static bool operator !=(SharpeRatioCalculator left, int right)
        {
            if (ReferenceEquals(left, null)) return true;
            return left.SharpeRatio != right;
        }

        /// <summary>
        /// Determines if the specified value is equal to the indicator's current value
        /// </summary>
        public static bool operator ==(int left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return left == right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the specified value is not equal to the indicator's current value
        /// </summary>
        public static bool operator !=(int left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return true;
            return left != right.SharpeRatio;
        }
        /// <summary>
        /// Determines if the indicator's current value is greater than the specified value
        /// </summary>
        public static bool operator >(SharpeRatioCalculator left, long right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio > right;
        }

        /// <summary>
        /// Determines if the indicator's current value is less than the specified value
        /// </summary>
        public static bool operator <(SharpeRatioCalculator left, long right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio < right;
        }

        /// <summary>
        /// Determines if the specified value is greater than the indicator's current value
        /// </summary>
        public static bool operator >(long left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return left > right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the specified value is less than the indicator's current value
        /// </summary>
        public static bool operator <(long left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return left < right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the indicator's current value is greater than or equal to the specified value
        /// </summary>
        public static bool operator >=(SharpeRatioCalculator left, long right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio >= right;
        }

        /// <summary>
        /// Determines if the indicator's current value is less than or equal to the specified value
        /// </summary>
        public static bool operator <=(SharpeRatioCalculator left, long right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio <= right;
        }

        /// <summary>
        /// Determines if the specified value is greater than or equal to the indicator's current value
        /// </summary>
        public static bool operator >=(long left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return left >= right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the specified value is less than or equal to the indicator's current value
        /// </summary>
        public static bool operator <=(long left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return left <= right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the indicator's current value is equal to the specified value
        /// </summary>
        public static bool operator ==(SharpeRatioCalculator left, long right)
        {
            if (ReferenceEquals(left, null)) return false;
            return left.SharpeRatio == right;
        }

        /// <summary>
        /// Determines if the indicator's current value is not equal to the specified value
        /// </summary>
        public static bool operator !=(SharpeRatioCalculator left, long right)
        {
            if (ReferenceEquals(left, null)) return true;
            return left.SharpeRatio != right;
        }

        /// <summary>
        /// Determines if the specified value is equal to the indicator's current value
        /// </summary>
        public static bool operator ==(long left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return false;
            return left == right.SharpeRatio;
        }

        /// <summary>
        /// Determines if the specified value is not equal to the indicator's current value
        /// </summary>
        public static bool operator !=(long left, SharpeRatioCalculator right)
        {
            if (ReferenceEquals(right, null)) return true;
            return left != right.SharpeRatio;
        }
        
        public override bool Equals(Object right)
	    {
	        // If parameter is null return false.
	        if (right == null)
	        {
	            return false;
	        }
	
	        // Return true if the fields match:
	        return (this == right);
	    }
	    
	    public override int GetHashCode()
		{
		    int hash = 13;
		    foreach (decimal wSymbolRatio in mSymbolsRatios)
		    {
		    	hash = (hash * 7) + wSymbolRatio.GetHashCode();
		    }
		    hash = (hash * 7) + mVolatilityFactor.GetHashCode();
		    hash = (hash * 7) + SharpeRatio.GetHashCode();
		    return hash;
		}
	}

}
using QuantConnect.Data.Market;
using System;

namespace QuantConnect {

    //
    // Test for SharpeRatioCalculator
    //
    /// <summary>
    /// 
    /// This test verifies that the SharpeRatioCalculator returns values that are at least proportional to 
    /// test runs from the real algorithm, for different time periods, with the same parameters.
    ///
    /// How to test it:
    /// - In Main.cs, change the allocation to 100% SharpeRatioCalculatorTest (mAllocationRatioSRCTEST = 1.0m)
    /// - Run the test
    /// - In the backtests statistics section, copy the 3-months SharpeRatio values in an Excel file
    /// - Open the graph "Sharpe Ratio three months"
    /// - For about 2 years of data, manually copy in the Excel file the values of the calculated sharpe ratios, at the same dates as the algo statistics
    /// - See if there is a correlation
    ///
    /// Results so far: quite poor (analysis done from April 2015 to December 2016)
    /// Correlation = 0.268
    ///
    /// Data results:
    ///
    ///	Date		3 Months, algo	3 Months, SRC calculator
	/// 04/30/2015	-0.014354245	-0.0454
	/// 05/31/2015	-0.013994576	-0.0341
	/// 06/30/2015	-0.045307418	-0.1322
	/// 07/31/2015	-0.002708537	-0.0005
	/// 08/31/2015	-0.007749081	-0.0385
	/// 09/30/2015	-0.003662463	-0.0183
	/// 10/31/2015	-0.014735746	 0.0008
	/// 11/30/2015	 0.011244831	 0.0962
	/// 12/31/2015	-0.007871732	 0.0992
	/// 01/31/2016	-0.013966913	-0.0727
	/// 02/29/2016	-0.001043126	 0.0296
	/// 03/31/2016	-0.01398189		 0.1413
	/// 04/30/2016	-0.018236248	 0.2148
	/// 05/31/2016	-0.009374347	 0.1655
	/// 06/30/2016	-0.008349114	 0.1858
	/// 07/31/2016	-0.014002565	 0.3271
	/// 08/31/2016	-0.010672807	 0.2293
	/// 09/30/2016	-0.003444261	 0.0323
	/// 10/31/2016	-0.007270203	-0.0989
	/// 11/30/2016	-0.015016703	-0.1928
	/// 12/31/2016	-0.020562391	-0.1895
    ///
    /// À faire: Faire les calculs de sharpe ratio et moving average, manuellement, dans Excel.
    /// Pour faire ça, faire logger la valeur du portfolio à chaque jour.
    ///
    /// Ok, j'ai complété le test manuellement dans Excel. Le calcul du Sharpe ratio manuel donne bien le résultat de l'indicateur.
    /// Possiblement que c'est parce que QC calcule le sharpe ratio basé sur des gains de close - open, et moi close - past close.
    ///
    /// </summary>
    public class Test_SRC : SubAlgorithm
    {
    	// Strategy parameters
        private string mSymbol1 = 					"SPY";
        private string mSymbol2 = 					"TLT";
        
        private SharpeRatioCalculator testSharpeRatioCalculator;
		public Test_SRC(PortfolioOfStrategies iAlgorithm, Resolution iResolution, decimal iAllocationRatio, int iStartYear, bool iRebalanceOnLaunch) : base(iAlgorithm, iResolution, iAllocationRatio, iStartYear, iRebalanceOnLaunch)
		{
		}
        public override void Initialize_Specific()
        {
        	// Override start and end date for this test only
        	SetStartDate(2015,01,01);
            SetEndDate(DateTime.Today.AddDays(-1));
			mDataFeedFrequency = "Daily";
	        
            AddSecurity(SecurityType.Equity, mSymbol1, mResolution, true, 3, false);
            AddSecurity(SecurityType.Equity, mSymbol2, mResolution, true, 3, false);
	        
	        testSharpeRatioCalculator = SRC(63, 1);
        }
        

        public override void OnData_Specific(TradeBars data)
        {
	        mLastAllocationAmount = mAllocationAmount;
	          
	        if (mFirstPass)
            {
            	SetHoldings(mSymbol1,0.5m);
            	SetHoldings(mSymbol2,0.5m);
            }
            
            testSharpeRatioCalculator.AddObservation(mAllocationAmount);
	          
            
            Plot("SharpeRatio three months", "Sharpe Ratio", testSharpeRatioCalculator);
            Plot("SharpeRatio three months", "Moving average", testSharpeRatioCalculator);
        }
		
		protected override bool IsDataValid(TradeBars iData)
        {
        	bool wValid = true;
            
            wValid &= iData.ContainsKey(mSymbol1);
            wValid &= iData.ContainsKey(mSymbol2);
			
            return wValid;
        }
    }
}
namespace QuantConnect {

    public class CorrelationCalculator
	{
	    public CorrelationCalculator(int period)
	    {
	        _period = period;
	        _window1 = new double[period];
	        _window2 = new double[period];
	    }
	
	    public double Correlation 
	    {
	        get { return _correlation; }
	    }
	
	    public bool HasFullPeriod
	    {
	        get { return _num_added >= _period; }
	    }
	
	    public int N
	    {
	        get { return Math.Min(_num_added, _period); }
	    }
	
	    public void AddObservation(double iValue1, double iValue2)
	    {
	        // Window is treated as a circular buffer.
	        var ndx = _num_added % _period;
	        _window1[ndx] = iValue1; // add new observation
	        _window2[ndx] = iValue2; // add new observation
	        _num_added++;
	
	        // Update correlation coefficient
        	int wNumElements = N;
            double[] array_xy = new double[wNumElements];
			double[] array_xp2 = new double[wNumElements];
			double[] array_yp2 = new double[wNumElements];
			double sum_xy = 0;
			double sum_xpow2 = 0;
			double sum_ypow2 = 0;
			for (int i = 0; i < wNumElements; i++)
			    array_xy[i] = _window1[i] * _window2[i];
			for (int i = 0; i < wNumElements; i++)
			    array_xp2[i] = Math.Pow(_window1[i], 2.0);
			for (int i = 0; i < wNumElements; i++)
			    array_yp2[i] = Math.Pow(_window2[i], 2.0);
			double sum_x = 0;
			double sum_y = 0;
			for (int i = 0; i < wNumElements; i++)
			{
				sum_x += _window1[i];
				sum_y += _window2[i];
				sum_xy += array_xy[i];
				sum_xpow2 += array_xp2[i];
				sum_ypow2 += array_yp2[i];
			}

			double Ex2 = Math.Pow(sum_x, 2.00);
			double Ey2 = Math.Pow(sum_y, 2.00);
			 
			_correlation = 
			(_window1.Length * sum_xy - sum_x * sum_y) /
			Math.Sqrt((_window1.Length * sum_xpow2 - Ex2) * (_window1.Length * sum_ypow2 - Ey2));
	    }
	
	    private readonly int _period;
	    private readonly double[] _window1;
	    private readonly double[] _window2;
	    private int _num_added;
	    private double _correlation;
	}
}
namespace QuantConnect {

    public class MovingAverageCalculator
	{
	    public MovingAverageCalculator(int period)
	    {
	        _period = period;
	        _window = new double[period];
	    }
	
	    public double Average 
	    {
	        get { return _average; }
	    }
	
	    public double StandardDeviation
	    {
	        get 
	        {
	            var variance = Variance;
	            if (variance >= double.Epsilon)
	            {
	                var sd = Math.Sqrt(variance);
	                return double.IsNaN(sd) ? 0.0 : sd;
	            }
	            return 0.0;
	        }
	    }
	
	    public double Variance
	    {
	        get 
	        { 
	            var n = N;
	            return n > 1 ? _variance_sum / (n - 1) : 0.0; 
	        }
	    }
	
	    public bool HasFullPeriod
	    {
	        get { return _num_added >= _period; }
	    }
	
	    public IEnumerable<double> Observations
	    {
	        get { return _window.Take(N); }
	    }
	
	    public int N
	    {
	        get { return Math.Min(_num_added, _period); }
	    }
	
	    public void AddObservation(double observation)
	    {
	        // Window is treated as a circular buffer.
	        var ndx = _num_added % _period;
	        var old = _window[ndx];     // get value to remove from window
	        _window[ndx] = observation; // add new observation in its place.
	        _num_added++;
	
	        // Update average and standard deviation using deltas
	        var old_avg = _average;
	        if (_num_added <= _period)
	        {
	            var delta = observation - old_avg;
	            _average += delta / _num_added;
	            _variance_sum += (delta * (observation - _average));
	        } 
	        else // use delta vs removed observation.
	        {
	            var delta = observation - old;
	            _average += delta / _period;
	            _variance_sum += (delta * ((observation - _average) + (old - old_avg)));
	        }
	    }
	
	    private readonly int _period;
	    private readonly double[] _window;
	    private int _num_added;
	    private double _average;
	    private double _variance_sum;
	}

}
using QuantConnect.Data.Market;
using System;
using System.Collections.Generic;
using System.Linq;

namespace QuantConnect
{
    /// <summary>
    /// 
    /// Universal Investment Strategy (UIS) as described here: http://seekingalpha.com/article/2714185-the-spy-tlt-universal-investment-strategy
    ///
    /// Best config so far (for long):
    /// Log("Backtesting with following parameters:");
    /// Log("Symbol1					>> " + UPRO);
    /// Log("Symbol2					>> " + TMF);
    /// Log("Symbol3					>> " + SPXU);
    /// Log("Symbol4					>> " + TMV);
    /// Log("Use short					>> " + false);
    /// Log("Leverage					>> " + 0.98);
    /// Log("Minimum Rebalance Period	>> " + 1);
    /// Log("Start year					>> " + 2010);
    /// Log("Sharpe lookback			>> " + 63);
    /// Log("Sharpe volatility factor	>> " + 2.8);
    ///
    /// Best config so far (for short):
    /// Log("Backtesting with following parameters:");
    /// Log("Symbol1					>> " + UPRO);
    /// Log("Symbol2					>> " + TMF);
    /// Log("Symbol3					>> " + SPXU);
    /// Log("Symbol4					>> " + TMV);
    /// Log("Use short					>> " + true);
    /// Log("Leverage					>> " + 0.98);
    /// Log("Minimum Rebalance Period	>> " + 21);
    /// Log("Start year					>> " + 2010);
    /// Log("Sharpe lookback			>> " + 63);
    /// Log("Sharpe volatility factor	>> " + 2.8);
    ///
    /// </summary>
    public class UIS : SubAlgorithm
    {
    	// Strategy parameters
        private string mSymbol1 = 					"SPY";
        private string mSymbol2 = 					"TLT";
        private string mSymbol3 = 					"SPXU";
        private string mSymbol4 = 					"TMV";
        private bool mUseShort = 					false;
        private bool mUseCorrelationExit =			true;	// Cash exit when the correlation between UPRU and TMF is positive, for a 1, 2, and 3 months lookback period. Does not exit ZIV positions.
        private int mMinimumRebalancePeriod = 		1;
        private int mSharpeLookback = 				63; // 63
        private decimal mSharpeVolatilityFactor = 	2.8m; // 2.8
        
        private SharpeRatioCalculator mMaxSharpeCombination;
        private CorrelationCalculator mCorrel2Weeks;
        private CorrelationCalculator mCorrel1Month;
        private CorrelationCalculator mCorrel2Month;
        private CorrelationCalculator mCorrel3Month;
        private int mDaysCounter = 0;
        private List<SharpeRatioCalculator> mSrcList;
        private decimal mLastRatio1 = 0;
        private decimal mLastRatio2 = 0;
        bool mCashExit = false;
        bool mCashExit_previous = false;
        bool mBuyBackIn = false;
        DateTime mLastHistoryCallsDate = DateTime.MinValue;
        List<TradeBar> mTradeBarHistorySymbol1;
        List<TradeBar> mTradeBarHistorySymbol2;

		public UIS(PortfolioOfStrategies iAlgorithm, Resolution iResolution, decimal iAllocationRatio, int iStartYear, bool iRebalanceOnLaunch) : base(iAlgorithm, iResolution, iAllocationRatio, iStartYear, iRebalanceOnLaunch)
		{
			if (LiveMode)
			{
				mDataFeedFrequency = "Minute";
			}
			else
			{
			mDataFeedFrequency = "Daily"; // Needs to stay daily or faster, for correlation exits and historical performances calculation
			}
			mRebalanceFrequency = "Weekly";
			mName = "UIS";
		}
		
        public override void Initialize_Specific()
        {
        	if (EnableLogs)
        	{
	        	Log("UIS Strategy: Backtesting with following parameters:");
	        	Log("\tSymbol1                    >> " + mSymbol1);
		        Log("\tSymbol2                    >> " + mSymbol2);
		        if (mUseShort)
		        {
		        	Log("\tSymbol3                    >> " + mSymbol3);
		        	Log("\tSymbol4                    >> " + mSymbol4);
		        }
		        Log("\tUseShort                   >> " + mUseShort);
		        Log("\tMinimum Rebalance Period   >> " + mMinimumRebalancePeriod);
		        Log("\tStart year                 >> " + mStartYear);
		        Log("\tSharpe lookback            >> " + mSharpeLookback);
		        Log("\tSharpe volatility factor   >> " + mSharpeVolatilityFactor);
        	}
	        
            AddSecurity(SecurityType.Equity, mSymbol1, mResolution, true, 3, false);
            AddSecurity(SecurityType.Equity, mSymbol2, mResolution, true, 3, false);
			if (mUseShort)
	        {
	        	AddSecurity(SecurityType.Equity, mSymbol3, mResolution, true, 3, false);
            	AddSecurity(SecurityType.Equity, mSymbol4, mResolution, true, 3, false);
	        }
            mTradeBarHistorySymbol1 = new List<TradeBar>();
            mTradeBarHistorySymbol2 = new List<TradeBar>();

            RecalculateSharpeRatios(mSharpeLookback, mSharpeVolatilityFactor, ref mSrcList);
        }

        public override void OnData_Specific(TradeBars data)
        {
            mDaysCounter = mDaysCounter - 1;
            
            RecalculateSharpeRatios(mSharpeLookback, mSharpeVolatilityFactor, ref mSrcList);
            
            // For backtesting purposes only, exclude the discontinuity that occured in the data on Aug 22-25 2016
            if (Time.Date >= DateTime.Parse("08/22/2016") && Time.Date <= DateTime.Parse("08/26/2016"))
            {
            	if (mUseShort)
        		{
	                Trade(data, mSymbol3, 0, mSymbol4, 0);
        		}
        		else
        		{
        			Trade(data, mSymbol1, 0, mSymbol2, 0);
        		}
            	return;
            }
            
            decimal wRatio1 = 0.5m;
            decimal wRatio2 = 0.5m;
            if (mSrcList[0].IsReady)
            {
            	mMaxSharpeCombination = mSrcList.Select( (value, index) => new { Value = value, Index = index } ).Aggregate( (a, b) => (a.Value > b.Value) ? a : b ).Value;
            	wRatio1 = mMaxSharpeCombination.mSymbolsRatios[0];
            	wRatio2 = mMaxSharpeCombination.mSymbolsRatios[1];
            }

            if (mFirstPass == true || mDaysCounter <= 0 || mLastRatio1 != wRatio1 || mLastRatio2 != wRatio2)
            {
            	mDaysCounter = mMinimumRebalancePeriod;
            	
            	if (EnableLogs)
            	{
            		Log(" ");
	            	Log("Rebalancing:");
            	}
            	
	            if (mSrcList[0].IsReady)
	            {
	            	mMaxSharpeCombination = mSrcList.Select( (value, index) => new { Value = value, Index = index } ).Aggregate( (a, b) => (a.Value > b.Value) ? a : b ).Value;
					
					if (EnableLogs)
	            	{
		                Log("     Max Sharpe Combination >> " + mSymbol1 + " " + (mMaxSharpeCombination.mSymbolsRatios[0] * 100).ToString ("#.#") + "%,  " + mSymbol2 + " " + (mMaxSharpeCombination.mSymbolsRatios[1] * 100).ToString ("#.#") + "%.");
	            	}
	            	
	            	decimal wSymbol1Ratio = mMaxSharpeCombination.mSymbolsRatios[0];
        			decimal wSymbol2Ratio = mMaxSharpeCombination.mSymbolsRatios[1];
					
					if (mUseCorrelationExit)
					{
	            		// Cash exit when the correlation between UPRU and TMF is positive, for a 1, 2, and 3 months lookback period.
	            		if (mCorrel1Month.Correlation > 0 && mCorrel2Month.Correlation > 0 && mCorrel3Month.Correlation > 0)
	            		{
	            			wSymbol1Ratio = 0;
	            			wSymbol2Ratio = 0;
	            			mCashExit = true;
	            			
	            			if (EnableLogs)
			            	{
			            		Log("Cash exit: Correlation between UPRO and TMF is positive for 1, 2, and 3 months lookback period.");
			            	}
	            		}
	            		else if (mCashExit == true && mBuyBackIn == false)
	            		{
	            			mCashExit = false;
	            			mBuyBackIn = true;
	            		}
					}
					
					// Trade if it it time to trade, or if there is cash exit toggle or buy back in toggle
	            	if ((mCashExit && !mCashExit_previous) || mBuyBackIn || IsTimeToRebalance())
					{
						if (mUseShort)
	            		{
			                Trade(data, mSymbol3, -wSymbol1Ratio, mSymbol4, -wSymbol2Ratio);
	            		}
	            		else
	            		{
	            			Trade(data, mSymbol1, wSymbol1Ratio, mSymbol2, wSymbol2Ratio);
	            		}
	            		
	            		mBuyBackIn = false;
					}
	                mCashExit_previous = mCashExit;
	            }
	            else
	            {
		            if (EnableLogs) Log("     Sharpe not ready       >> " + mSymbol1 + " 50%,  " + mSymbol2 + " 50%.");
	                
	                if (IsTimeToRebalance())
					{
		            	// If sharpe ratio not ready yet, use a 50%-50% split between UPRO and TMF
	                	if (mUseShort)
	            		{
			                Trade(data, mSymbol3, -0.5m, mSymbol4, -0.5m);
	            		}
	            		else
	            		{
	            			Trade(data, mSymbol1, 0.5m, mSymbol2, 0.5m);
	            		}
					}
	            }
	            
	            mLastAllocationAmount = mAllocationAmount;
	            mLastRatio1 = wRatio1;
	            mLastRatio2 = wRatio2;
            }

            decimal wSymbol1Percentage;
            decimal wSymbol2Percentage;
            
            if (mSrcList[0].IsReady && mMaxSharpeCombination != null)
            {
            	wSymbol1Percentage = mMaxSharpeCombination.mSymbolsRatios[0] * 100;
            	wSymbol2Percentage = mMaxSharpeCombination.mSymbolsRatios[1] * 100;
            }
            else
            {
            	wSymbol1Percentage = 50;
            	wSymbol2Percentage = 50;
            }
			
            Plot(mSymbol1 + "-" + mSymbol2 + " Split", mSymbol1 + " (%)", wSymbol1Percentage);
            Plot(mSymbol1 + "-" + mSymbol2 + " Split", mSymbol2 + " (%)", wSymbol2Percentage);
            Plot(mSymbol1 + "-" + mSymbol2 + " Correlation", "Correl 2 Weeks", mCorrel2Weeks.Correlation*100);
            Plot(mSymbol1 + "-" + mSymbol2 + " Correlation", "Correl 1 Month", mCorrel1Month.Correlation*100);
            Plot(mSymbol1 + "-" + mSymbol2 + " Correlation", "Correl 2 Months", mCorrel2Month.Correlation*100);
            Plot(mSymbol1 + "-" + mSymbol2 + " Correlation", "Correl 3 Months", mCorrel3Month.Correlation*100);
            Plot(mSymbol1 + "-" + mSymbol2 + " Correlation", "0", 0);
        }
        
        protected override bool IsDataValid(TradeBars iData)
        {
        	bool wValid = true;
            
            if (!mUseShort)
            {
            	wValid &= iData.ContainsKey(mSymbol1);
            	wValid &= iData.ContainsKey(mSymbol2);
            }
            if (mUseShort)
            {
            	wValid &= iData.ContainsKey(mSymbol3);
            	wValid &= iData.ContainsKey(mSymbol4);
            }
            return wValid;
        }
        
        private void RecalculateSharpeRatios(int iLookback, decimal iVolatilityFactor, ref List<SharpeRatioCalculator> iSrcList)
        {
            iSrcList = new List<SharpeRatioCalculator>();
            mCorrel2Weeks = new CorrelationCalculator(10);
            mCorrel1Month = new CorrelationCalculator(21);
            mCorrel2Month = new CorrelationCalculator(42);
            mCorrel3Month = new CorrelationCalculator(63);
			
        	int granularity = 15;
            for (int i = 0; i <= granularity; i++)
	        {
	        	List<decimal> wSymbolsRatios = new List<decimal>();
	        	wSymbolsRatios.Add(1/(decimal)granularity * i);
	        	wSymbolsRatios.Add(1.0m - (1/(decimal)granularity * i));
	        	iSrcList.Add(SRC(wSymbolsRatios, iLookback, iVolatilityFactor));
	        }
	        
            // get the last 100 daily bars, once a day
            if (mAlgorithm.Time.Date > mLastHistoryCallsDate.Date)
            {
                mLastHistoryCallsDate = mAlgorithm.Time;
                mTradeBarHistorySymbol1 = History(mSymbol1, 100, Resolution.Daily).ToList();
                mTradeBarHistorySymbol2 = History(mSymbol2, 100, Resolution.Daily).ToList();
            }

            for (int i = 0; i < mTradeBarHistorySymbol1.Count(); i++)
            {
            	for (int j = 0; j < iSrcList.Count; j++)
		        {
		        	List<TradeBar> wData = new List<TradeBar>();
		        	wData.Add(mTradeBarHistorySymbol1[i]);
		        	wData.Add(mTradeBarHistorySymbol2[i]);
		            iSrcList[j].AddObservation(wData);
		        }
		        mCorrel2Weeks.AddObservation((double)mTradeBarHistorySymbol1[i].Close, (double)mTradeBarHistorySymbol2[i].Close);
		        mCorrel1Month.AddObservation((double)mTradeBarHistorySymbol1[i].Close, (double)mTradeBarHistorySymbol2[i].Close);
		        mCorrel2Month.AddObservation((double)mTradeBarHistorySymbol1[i].Close, (double)mTradeBarHistorySymbol2[i].Close);
		        mCorrel3Month.AddObservation((double)mTradeBarHistorySymbol1[i].Close, (double)mTradeBarHistorySymbol2[i].Close);
		    }
        }
        
    }
}
using QuantConnect.Data.Market;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;
using System.Linq;

namespace QuantConnect
{
    /// <summary>
	/// 
	/// See here for the strategy: https://logical-invest.com/portfolio-items/the-gold-etf-currency-strategy/
	///
	/// This is a semi-automated algorithm that uses signals from Logical Invest, stored in a csv file on Dropbox.
	///
    /// </summary>
    public class GLD_LI_SIGNALS : SubAlgorithm
    {
        // Strategy parameters
        private bool mRebalanceOnChange = 			true;
        
        // Other variables
        private string mSymbol1 = 					"";
        private string mSymbol2 = 					"";
        private decimal mSymbol1Ratio = 			0.0m;
        private decimal mSymbol2Ratio = 			0.0m;
        private bool mReadyToTrade = 				false;
        
        private Dictionary<string, string> mValuesDictionary;
        private string mDropboxFileDirectDownloadLink = "";
  
		public GLD_LI_SIGNALS(PortfolioOfStrategies iAlgorithm, Resolution iResolution, decimal iAllocationRatio, int iStartYear, bool iRebalanceOnLaunch) : base(iAlgorithm, iResolution, iAllocationRatio, iStartYear, iRebalanceOnLaunch)
		{
			if (LiveMode)
			{
				mDataFeedFrequency = "Minute";
			}
			else
			{
				mDataFeedFrequency = "Daily";
			}
			mRebalanceFrequency = "Monthly";
			mDropboxFileDirectDownloadLink = "https://dropbox.com/s/ko9exryrs1ckojz/Algo%20Values%20Updater.csv?dl=1";
			mName = "GLD_LI_SINGALS";
		}
		
        public override void Initialize_Specific()
        {
            mValuesDictionary = new Dictionary<string, string>();
            ReadHistoryFromLogicalInvest("GLD", "https://logical-invest.com/wp-content/csvrepository/GLD-USD_return.html");
        }

        public override void OnData_Specific(TradeBars data)
        {
        	UpdateDictionary(Time, ref mValuesDictionary);
        	
        	if (!mKeepFeedingData)
        	{
        		bool wSomeValueHasChanged = false;
				bool wSuccess = RetrieveValuesFromDictionary(ref wSomeValueHasChanged);
				if (!wSuccess) return;
				
				if (!Securities.ContainsKey(mSymbol1)) AddSecurity(SecurityType.Equity, mSymbol1, mResolution, true, 3, false);
				if (!Securities.ContainsKey(mSymbol2)) AddSecurity(SecurityType.Equity, mSymbol2, mResolution, true, 3, false);
				
				if (IsTimeToRebalance() || (mRebalanceOnChange && wSomeValueHasChanged))
				{
					mKeepFeedingData = true;
					mReadyToTrade = true;
				}
        	}
			
			if (!IsDataValid(data)) return;
			
			if (mReadyToTrade) 
			{
				Trade(data, mSymbol1, mSymbol1Ratio, mSymbol2, mSymbol2Ratio);
				mKeepFeedingData = false;
				mReadyToTrade = false;
			}
			
			// TODO: Add plotting of symbols
        }
        
        protected override bool IsDataValid(TradeBars iData)
        {
        	if (mSymbol1 == "")
        	{
        		return true; // If the required data is not yet initialized, skip this.
        	}
        	else
        	{
        		bool wValid = true;
        		wValid &= iData.ContainsKey(mSymbol1);
	        	wValid &= iData.ContainsKey(mSymbol2);
				
	            return wValid;
        	}
        }
        
        
        //
        // Reads the desired values from the web and stores it in oValuesDictionary (Dictionary of variable name:value)
        // If in backtest mode and dates are in the past month or earlier, reads from LogicalInvest webpage directly.
        // If the date is in the current month, reads from the CSV file manually maintained on Dropbox.
        //
        private void UpdateDictionary(DateTime iTime, ref Dictionary<string, string> oValuesDictionary)
        {            
            DateTime wRealTime = mAlgorithm.Time;
            if ((iTime.Year != wRealTime.Year) || (iTime.Month != wRealTime.Month))
            {
            	oValuesDictionary = mHistoryDictionary[new DateTime(iTime.Year, iTime.Month, 1)];
            }
            else
            {
	            using (var client = new WebClient())
	            {
	                string file = "";
	                try  
					{  
					    // fetch the file from dropbox                
	                	file = client.DownloadString(mDropboxFileDirectDownloadLink);
					}
					catch
					{
						if (EnableLogs) Log("Error reading file from Dropbox: " + mDropboxFileDirectDownloadLink);
						return;
					} 

	                var lines = file.Replace("\r", String.Empty).Split(new[] { Environment.NewLine },StringSplitOptions.None);
                
	                foreach (string line in lines)
	                {
	                	List<string> wKeyVal = line.Split(',').ToList();
	                	if (wKeyVal[0] == "") continue;
                	
	                	string wKey = wKeyVal[0];
	                	string wValue = "";
	                	if (wKeyVal.Count > 1)
	                	{
	                		wValue = wKeyVal[1];
	                	}
	                	if(!oValuesDictionary.ContainsKey(wKey))
	                	{
	                		oValuesDictionary.Add(wKey, wValue);
	                	}
	                	else
	                	{
	                		oValuesDictionary[wKey] = wValue;
	                	}
	                }
	            }
            }
        }
        
        //
        // Gets the symbol values from mValuesDictionary, and stores them in mSymbol1, mSymbol2, ... , mSymbol1Ratio, mSymbol2Ratio, ...
        // Needs to have called UpdateDictionary() prior to this.
        //
        private bool RetrieveValuesFromDictionary(ref bool oSomeValueHasChanged)
        {
        	if (!mValuesDictionary.ContainsKey("GLD_Symbol1")) 			Log("Error: Could not retrieve parameter GLD_Symbol1 from Dropbox.");
			if (!mValuesDictionary.ContainsKey("GLD_Symbol1_Ratio")) 	Log("Error: Could not retrieve parameter GLD_Symbol1_Ratio from Dropbox.");
			if (!mValuesDictionary.ContainsKey("GLD_Symbol2"))			Log("Error: Could not retrieve parameter GLD_Symbol2 from Dropbox.");
			if (!mValuesDictionary.ContainsKey("GLD_Symbol2_Ratio")) 	Log("Error: Could not retrieve parameter GLD_Symbol2_Ratio from Dropbox.");
			
			if (!mValuesDictionary.ContainsKey("GLD_Symbol1") ||
				!mValuesDictionary.ContainsKey("GLD_Symbol1_Ratio") ||
				!mValuesDictionary.ContainsKey("GLD_Symbol2") ||
				!mValuesDictionary.ContainsKey("GLD_Symbol2_Ratio"))
			{
				return false;
			}
			
			oSomeValueHasChanged = 
				mSymbol1 != mValuesDictionary["GLD_Symbol1"] ||
				mSymbol2 != mValuesDictionary["GLD_Symbol2"] ||
				mSymbol1Ratio != Convert.ToDecimal(mValuesDictionary["GLD_Symbol1_Ratio"]) ||
				mSymbol2Ratio != Convert.ToDecimal(mValuesDictionary["GLD_Symbol2_Ratio"]);
			
			mSymbol1 = mValuesDictionary["GLD_Symbol1"];
			mSymbol2 = mValuesDictionary["GLD_Symbol2"];
			mSymbol1Ratio = Convert.ToDecimal(mValuesDictionary["GLD_Symbol1_Ratio"]);
			mSymbol2Ratio = Convert.ToDecimal(mValuesDictionary["GLD_Symbol2_Ratio"]);
			
			return true;
        }
    }
}
using QuantConnect.Data.Market;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;

namespace QuantConnect
{
    /// <summary>
	/// 
	/// See here for the strategy: https://logical-invest.com/portfolio-items/3x-leveraged-universal-investment-strategy/
	///
	/// This is a fully automated algorithm that uses signals from Logical Invest.
	/// Signal emails from Logical Invest are automatically stored as text files in Dropbox, and read by this algorithm.
	///
    /// </summary>
    public class NASDAQ_LI_SIGNALS : SubAlgorithm
    {
        // Strategy parameters
        private bool mRebalanceOnChange = 			true;
        
        // Other variables
        private string mSymbol1 = 					"";
        private string mSymbol2 = 					"";
        private string mSymbol3 = 					"";
        private string mSymbol4 = 					"";
        private string mSymbol5 = 					"";
        private decimal mSymbol1Ratio = 			0.0m;
        private decimal mSymbol2Ratio = 			0.0m;
        private decimal mSymbol3Ratio = 			0.0m;
        private decimal mSymbol4Ratio = 			0.0m;
        private decimal mSymbol5Ratio = 			0.0m;
        private bool mReadyToTrade = 				false;
        private bool mReadFromCvsInsteadOfEmail = 	false;
        
        private Dictionary<string, string> mValuesDictionary;
        private string mDropboxFileDirectDownloadLink = "";
  
		public NASDAQ_LI_SIGNALS(PortfolioOfStrategies iAlgorithm, Resolution iResolution, decimal iAllocationRatio, int iStartYear, bool iRebalanceOnLaunch) : base(iAlgorithm, iResolution, iAllocationRatio, iStartYear, iRebalanceOnLaunch)
		{
			if (LiveMode)
			{
				mDataFeedFrequency = "Minute"; // Needs to stay daily or faster, for historical performances calculation
			}
			else
			{
				mDataFeedFrequency = "Daily"; // Needs to stay daily or faster, for historical performances calculation
			}
			mRebalanceFrequency = "Monthly";
			mName = "NASDAQ_LI_SIGNALS";
			if (mReadFromCvsInsteadOfEmail)
			{
				// To read from the manual csv file, in "Dropbox\Public\Algo Values Updater.csv"
				mDropboxFileDirectDownloadLink = "https://www.dropbox.com/s/ko9exryrs1ckojz/Algo%20Values%20Updater.csv?dl=1"; 
			}
			else
			{
				// To read from the logical invest email text file, in "Dropbox\Public\Logical Invest Rebalance Emails\Nasdaq100SignalEmail.txt"
				// Thie text file is automatically dropped there everytime a new email comes in, using Zapier.com to automate it
				mDropboxFileDirectDownloadLink = "https://www.dropbox.com/s/gwf88v90h4pq5ho/Nasdaq100SignalEmail.txt?dl=1"; 
			}
		}
		
        public override void Initialize_Specific()
        {
            mValuesDictionary = new Dictionary<string, string>();
            ReadHistoryFromLogicalInvest("NASDAQ", "https://logical-invest.com/wp-content/csvrepository/NASDAQ100_return.html");
        }

        public override void OnData_Specific(TradeBars data)
        {
        	UpdateDictionary(Time, ref mValuesDictionary);
        	
        	if (!mKeepFeedingData)
        	{
        		bool wSomeValueHasChanged = false;
				bool wSuccess = RetrieveValuesFromDictionary(ref wSomeValueHasChanged);
				if (!wSuccess) return;
				
				if (!Securities.ContainsKey(mSymbol1)) AddSecurity(SecurityType.Equity, mSymbol1, mResolution, true, 3, false);
				if (!Securities.ContainsKey(mSymbol2)) AddSecurity(SecurityType.Equity, mSymbol2, mResolution, true, 3, false);
				if (!Securities.ContainsKey(mSymbol3)) AddSecurity(SecurityType.Equity, mSymbol3, mResolution, true, 3, false);
				if (!Securities.ContainsKey(mSymbol4)) AddSecurity(SecurityType.Equity, mSymbol4, mResolution, true, 3, false);
				if (!Securities.ContainsKey(mSymbol5)) AddSecurity(SecurityType.Equity, mSymbol5, mResolution, true, 3, false);
				
				if (IsTimeToRebalance() || (mRebalanceOnChange && wSomeValueHasChanged))
				{
					mKeepFeedingData = true;
					mReadyToTrade = true;
				}
        	}
			
			if (!IsDataValid(data)) return;
			
			if (mReadyToTrade) 
			{
				Trade(data, mSymbol1, mSymbol1Ratio, mSymbol2, mSymbol2Ratio, mSymbol3, mSymbol3Ratio, mSymbol4, mSymbol4Ratio, mSymbol5, mSymbol5Ratio);
				mKeepFeedingData = false;
				mReadyToTrade = false;
			}
			
			// TODO: Add plotting of symbols
        }
        
        protected override bool IsDataValid(TradeBars iData)
        {
        	if (mSymbol1 == "")
        	{
        		return true; // If the required data is not yet initialized, skip this.
        	}
        	else
        	{
        		bool wValid = true;
        		wValid &= iData.ContainsKey(mSymbol1);
	        	wValid &= iData.ContainsKey(mSymbol2);
				wValid &= iData.ContainsKey(mSymbol3);
				wValid &= iData.ContainsKey(mSymbol4);
				wValid &= iData.ContainsKey(mSymbol5);
	            return wValid;
        	}
        }
        
        
        //
        // Reads the desired values from the web and stores it in oValuesDictionary (Dictionary of variable name:value)
        // If in backtest mode and dates are in the past month or earlier, reads from LogicalInvest webpage directly.
        // If the date is in the current month, reads from Dropbox, the email received from LogicalInvest.
        //
        private void UpdateDictionary(DateTime iTime, ref Dictionary<string, string> oValuesDictionary)
        {       
            DateTime wRealTime = mAlgorithm.Time;
            if ((iTime.Year != wRealTime.Year) || (iTime.Month != wRealTime.Month))
            {
            	oValuesDictionary = mHistoryDictionary[new DateTime(iTime.Year, iTime.Month, 1)];
            }
            else
            {
	            using (var client = new WebClient())
	            {
	                string file = "";
	                try  
					{  
					    // fetch the file from dropbox                
	                	file = client.DownloadString(mDropboxFileDirectDownloadLink);
					}
					catch
					{
						if (EnableLogs) Log("Error reading file from Dropbox: " + mDropboxFileDirectDownloadLink);
						return;
					} 

                	if (mReadFromCvsInsteadOfEmail)
	                {
	                	var lines = file.Replace("\r", String.Empty).Split(new[] { Environment.NewLine },StringSplitOptions.None);
	                	foreach (string line in lines)
		                {
		                	List<string> wKeyVal = line.Split(',').ToList();
		                	if (wKeyVal[0] == "") continue;
		                	
		                	string wKey = wKeyVal[0];
		                	string wValue = "";
		                	if (wKeyVal.Count > 1)
		                	{
		                		wValue = wKeyVal[1];
		                	}
		                	if(!oValuesDictionary.ContainsKey(wKey))
		                	{
		                		oValuesDictionary.Add(wKey, wValue);
		                	}
		                	else
		                	{
		                		oValuesDictionary[wKey] = wValue;
		                	}
		                }
	                }
	                else
	                {
	                	Regex r = new Regex("New allocations for your portfolio by ETF(.|\r\n)*?</table>", RegexOptions.IgnoreCase);
                        string wAllocationsSection = r.Match(file).Value;
                        
                        // For debugging
		                // Log("wAllocationsSection = " + wAllocationsSection);
                        
                        // Each match in wSymbolMatches will be of this format: ">FOXA - "
                        // Each symbol in wSymbols will be the actual ticker (Ex: "FOXA")
                        r = new Regex(">[A-Z]*? - ");
                        MatchCollection wSymbolMatches = r.Matches(wAllocationsSection);
                        var wSymbols = new List<string>();
                        foreach (Match match in wSymbolMatches)
                        {
                            string wSymbol = match.Value.Replace(">","").Replace(" - ","");
                            wSymbols.Add(wSymbol);
                        }
                        
                        // Each match in wPercentMatches will be of this format: "<td>30.0%</td>"
                        // Each value in wAllocations will be the actual decimal allocation, as a string (Ex: "0.010")
                        r = new Regex("<td>.*?%</td>");
                        MatchCollection wPercentMatches = r.Matches(wAllocationsSection);
                        var wAllocations = new List<string>();
                        foreach (Match match in wPercentMatches)
                        {
                            string wAllocationPercentage = match.Value.Replace("<td>","").Replace("%","").Replace("</td>","");
                            string wAllocationDecimal = "0." + wAllocationPercentage.Replace(".","");
                            wAllocations.Add(wAllocationDecimal);
                        }
                        // Remove the last percentage entry, which is the total percentage allocation
                        if(wAllocations.Any())
                        {
                            wAllocations.RemoveAt(wAllocations.Count - 1);
                        }

		                // Each line in wLines2 will be of this format: "NASDAQ_Symbol1,AMZN" and "NASDAQ_Symbol1_Ratio,0.10"
		                var wLines2 = new List<string>();
		                for (int i = 0; i<wSymbols.Count(); i++)
		                {
		                	// For debugging
		                	// Log("wSymbols["+i+"] = " + wSymbols[i]);
		                	// Log("wAllocations["+i+"] = " + wAllocations[i]);

		                	string wSymbol = wSymbols[i]; // Ex: AMZN
		                	string wAllocationDecimal = wAllocations[i]; // Ex: 0.105
		                	
		                	wLines2.Add("NASDAQ_Symbol" + (i+1) + "," + wSymbol); // Ex: NASDAQ_Symbol1,AMZN
		                	wLines2.Add("NASDAQ_Symbol" + (i+1) + "_Ratio," + wAllocationDecimal); // Ex: NASDAQ_Symbol1_Ratio,0.105
		                }
		                
		                foreach (string line in wLines2)
		                {
		                	List<string> wKeyVal = line.Split(',').ToList();
		                	if (wKeyVal[0] == "") continue;
		                	
		                	string wKey = wKeyVal[0];
		                	string wValue = "";
		                	if (wKeyVal.Count > 1)
		                	{
		                		wValue = wKeyVal[1];
		                	}
		                	if(!oValuesDictionary.ContainsKey(wKey))
		                	{
		                		oValuesDictionary.Add(wKey, wValue);
		                	}
		                	else
		                	{
		                		oValuesDictionary[wKey] = wValue;
		                	}
		                }
		                
		                // For debugging
		                // foreach (KeyValuePair<string,string> wKeyValue in oValuesDictionary)
		                // {
		                // 	Log("Key = " + wKeyValue.Key + " - Value = " + wKeyValue.Value);
		                // }
	                }
	            }
            }
        }
        
        //
        // Gets the symbol values from mValuesDictionary, and stores them in mSymbol1, mSymbol2, ... , mSymbol1Ratio, mSymbol2Ratio, ...
        // Needs to have called UpdateDictionary() prior to this.
        //
        private bool RetrieveValuesFromDictionary(ref bool oSomeValueHasChanged)
        {
        	if (!mValuesDictionary.ContainsKey("NASDAQ_Symbol1")) 		Log("Error: Could not retrieve parameter NASDAQ_Symbol1 from Dropbox.");
			if (!mValuesDictionary.ContainsKey("NASDAQ_Symbol1_Ratio")) Log("Error: Could not retrieve parameter NASDAQ_Symbol1_Ratio from Dropbox.");
			if (!mValuesDictionary.ContainsKey("NASDAQ_Symbol2"))		Log("Error: Could not retrieve parameter NASDAQ_Symbol2 from Dropbox.");
			if (!mValuesDictionary.ContainsKey("NASDAQ_Symbol2_Ratio")) Log("Error: Could not retrieve parameter NASDAQ_Symbol2_Ratio from Dropbox.");
			if (!mValuesDictionary.ContainsKey("NASDAQ_Symbol3")) 		Log("Error: Could not retrieve parameter NASDAQ_Symbol3 from Dropbox.");
			if (!mValuesDictionary.ContainsKey("NASDAQ_Symbol3_Ratio")) Log("Error: Could not retrieve parameter NASDAQ_Symbol3_Ratio from Dropbox.");
			if (!mValuesDictionary.ContainsKey("NASDAQ_Symbol4"))		Log("Error: Could not retrieve parameter NASDAQ_Symbol4 from Dropbox.");
			if (!mValuesDictionary.ContainsKey("NASDAQ_Symbol4_Ratio")) Log("Error: Could not retrieve parameter NASDAQ_Symbol4_Ratio from Dropbox.");
			if (!mValuesDictionary.ContainsKey("NASDAQ_Symbol5")) 		Log("Error: Could not retrieve parameter NASDAQ_Symbol5 from Dropbox.");
			if (!mValuesDictionary.ContainsKey("NASDAQ_Symbol5_Ratio")) Log("Error: Could not retrieve parameter NASDAQ_Symbol5_Ratio from Dropbox.");
			
			if (!mValuesDictionary.ContainsKey("NASDAQ_Symbol1") ||
				!mValuesDictionary.ContainsKey("NASDAQ_Symbol1_Ratio") ||
				!mValuesDictionary.ContainsKey("NASDAQ_Symbol2") ||
				!mValuesDictionary.ContainsKey("NASDAQ_Symbol2_Ratio") ||
				!mValuesDictionary.ContainsKey("NASDAQ_Symbol3") ||
				!mValuesDictionary.ContainsKey("NASDAQ_Symbol3_Ratio") ||
				!mValuesDictionary.ContainsKey("NASDAQ_Symbol4") ||
				!mValuesDictionary.ContainsKey("NASDAQ_Symbol4_Ratio") ||
				!mValuesDictionary.ContainsKey("NASDAQ_Symbol5") ||
				!mValuesDictionary.ContainsKey("NASDAQ_Symbol5_Ratio"))
			{
				return false;
			}
			
			oSomeValueHasChanged = 
				mSymbol1 != mValuesDictionary["NASDAQ_Symbol1"] ||
				mSymbol2 != mValuesDictionary["NASDAQ_Symbol2"] ||
				mSymbol3 != mValuesDictionary["NASDAQ_Symbol3"] ||
				mSymbol4 != mValuesDictionary["NASDAQ_Symbol4"] ||
				mSymbol5 != mValuesDictionary["NASDAQ_Symbol5"] ||
				mSymbol1Ratio != Convert.ToDecimal(mValuesDictionary["NASDAQ_Symbol1_Ratio"]) ||
				mSymbol2Ratio != Convert.ToDecimal(mValuesDictionary["NASDAQ_Symbol2_Ratio"]) ||
				mSymbol3Ratio != Convert.ToDecimal(mValuesDictionary["NASDAQ_Symbol3_Ratio"]) ||
				mSymbol4Ratio != Convert.ToDecimal(mValuesDictionary["NASDAQ_Symbol4_Ratio"]) ||
				mSymbol5Ratio != Convert.ToDecimal(mValuesDictionary["NASDAQ_Symbol5_Ratio"]);
			
			mSymbol1 = mValuesDictionary["NASDAQ_Symbol1"];
			mSymbol2 = mValuesDictionary["NASDAQ_Symbol2"];
			mSymbol3 = mValuesDictionary["NASDAQ_Symbol3"];
			mSymbol4 = mValuesDictionary["NASDAQ_Symbol4"];
			mSymbol5 = mValuesDictionary["NASDAQ_Symbol5"];
			mSymbol1Ratio = Convert.ToDecimal(mValuesDictionary["NASDAQ_Symbol1_Ratio"]);
			mSymbol2Ratio = Convert.ToDecimal(mValuesDictionary["NASDAQ_Symbol2_Ratio"]);
			mSymbol3Ratio = Convert.ToDecimal(mValuesDictionary["NASDAQ_Symbol3_Ratio"]);
			mSymbol4Ratio = Convert.ToDecimal(mValuesDictionary["NASDAQ_Symbol4_Ratio"]);
			mSymbol5Ratio = Convert.ToDecimal(mValuesDictionary["NASDAQ_Symbol5_Ratio"]);
			
			return true;
        }
    }
}
using QuantConnect.Data.Market;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;

namespace QuantConnect
{
    /// <summary>
	/// 
	/// See here for the strategy: https://logical-invest.com/portfolio-items/the-gold-etf-currency-strategy/
	///
	/// This is a semi-automated algorithm that uses signals from Logical Invest, stored in a csv file on Dropbox.
	///
    /// </summary>
    public class UIS_LI_SIGNALS : SubAlgorithm
    {
        // Strategy parameters
        private bool mRebalanceOnChange = 			true;
        
        // Other variables
        private string mSymbol1 = 					"";
        private string mSymbol2 = 					"";
        private decimal mSymbol1Ratio = 			0.0m;
        private decimal mSymbol2Ratio = 			0.0m;
        private bool mReadyToTrade = 				false;
        
        private Dictionary<string, string> mValuesDictionary;
        private string mDropboxFileDirectDownloadLink = "";
  
		public UIS_LI_SIGNALS(PortfolioOfStrategies iAlgorithm, Resolution iResolution, decimal iAllocationRatio, int iStartYear, bool iRebalanceOnLaunch) : base(iAlgorithm, iResolution, iAllocationRatio, iStartYear, iRebalanceOnLaunch)
		{
			if (LiveMode)
			{
				mDataFeedFrequency = "Minute";
			}
			else
			{
				mDataFeedFrequency = "Daily";
			}
			mRebalanceFrequency = "Monthly";
			mName = "UIS_LI_SIGNALS";
			mDropboxFileDirectDownloadLink = "https://dropbox.com/s/ko9exryrs1ckojz/Algo%20Values%20Updater.csv?dl=1";
		}
		
        public override void Initialize_Specific()
        {
            mValuesDictionary = new Dictionary<string, string>();
            ReadHistoryFromLogicalInvest("UIS", "https://logical-invest.com/wp-content/csvrepository/UIS-SPXL-TMF_return.html");
        }

        public override void OnData_Specific(TradeBars data)
        {
        	UpdateDictionary(Time, ref mValuesDictionary);
        	
        	if (!mKeepFeedingData)
        	{
				bool wSomeValueHasChanged = false;
				bool wSuccess = RetrieveValuesFromDictionary(ref wSomeValueHasChanged);
				if (!wSuccess) return;
				
				if (!Securities.ContainsKey(mSymbol1)) AddSecurity(SecurityType.Equity, mSymbol1, mResolution, true, 3, false);
				if (!Securities.ContainsKey(mSymbol2)) AddSecurity(SecurityType.Equity, mSymbol2, mResolution, true, 3, false);
				
				if (IsTimeToRebalance() || (mRebalanceOnChange && wSomeValueHasChanged))
				{
					mKeepFeedingData = true;
					mReadyToTrade = true;
				}
        	}
			
			if (!IsDataValid(data)) return;
			
			if (mReadyToTrade) 
			{
				Trade(data, mSymbol1, mSymbol1Ratio, mSymbol2, mSymbol2Ratio);
				mKeepFeedingData = false;
				mReadyToTrade = false;
			}
			
			// TODO: Add plotting of symbols
        }
        
        protected override bool IsDataValid(TradeBars iData)
        {
        	if (mSymbol1 == "")
        	{
        		return true; // If the required data is not yet initialized, skip this.
        	}
        	else
        	{
        		bool wValid = true;
        		wValid &= iData.ContainsKey(mSymbol1);
	        	wValid &= iData.ContainsKey(mSymbol2);
				
	            return wValid;
        	}
        }
        
        //
        // Reads the desired values from the web and stores it in oValuesDictionary (Dictionary of variable name:value)
        // If in backtest mode and dates are in the past month or earlier, reads from LogicalInvest webpage directly.
        // If the date is in the current month, reads from the CSV file manually maintained on Dropbox.
        //
        private void UpdateDictionary(DateTime iTime, ref Dictionary<string, string> oValuesDictionary)
        {            
            DateTime wRealTime = mAlgorithm.Time;
            if ((iTime.Year != wRealTime.Year) || (iTime.Month != wRealTime.Month))
            {
            	oValuesDictionary = mHistoryDictionary[new DateTime(iTime.Year, iTime.Month, 1)];
            }
            else
            {
	            using (var client = new WebClient())
	            {
	                string file = "";
	                try  
					{  
					    // fetch the file from dropbox                
	                	file = client.DownloadString(mDropboxFileDirectDownloadLink);
					}
					catch
					{
						if (EnableLogs) Log("Error reading file from Dropbox: " + mDropboxFileDirectDownloadLink);
						return;
					} 
	                var lines = file.Replace("\r", String.Empty).Split(new[] { Environment.NewLine },StringSplitOptions.None);
                
	                foreach (string line in lines)
	                {
	                	List<string> wKeyVal = line.Split(',').ToList();
	                	if (wKeyVal[0] == "") continue;
                	
	                	string wKey = wKeyVal[0];
	                	string wValue = "";
	                	if (wKeyVal.Count > 1)
	                	{
	                		wValue = wKeyVal[1];
	                	}
	                	if(!oValuesDictionary.ContainsKey(wKey))
	                	{
	                		oValuesDictionary.Add(wKey, wValue);
	                	}
	                	else
	                	{
	                		oValuesDictionary[wKey] = wValue;
	                	}
	                }
	            }
            }
        }
        
        //
        // Gets the symbol values from mValuesDictionary, and stores them in mSymbol1, mSymbol2, ... , mSymbol1Ratio, mSymbol2Ratio, ...
        // Needs to have called UpdateDictionary() prior to this.
        //
        private bool RetrieveValuesFromDictionary(ref bool oSomeValueHasChanged)
        {
        	if (!mValuesDictionary.ContainsKey("UIS_Symbol1")) 			Log("Error: Could not retrieve parameter UIS_Symbol1 from Dropbox.");
			if (!mValuesDictionary.ContainsKey("UIS_Symbol1_Ratio")) 	Log("Error: Could not retrieve parameter UIS_Symbol1_Ratio from Dropbox.");
			if (!mValuesDictionary.ContainsKey("UIS_Symbol2"))			Log("Error: Could not retrieve parameter UIS_Symbol2 from Dropbox.");
			if (!mValuesDictionary.ContainsKey("UIS_Symbol2_Ratio")) 	Log("Error: Could not retrieve parameter UIS_Symbol2_Ratio from Dropbox.");
			
			if (!mValuesDictionary.ContainsKey("UIS_Symbol1") ||
				!mValuesDictionary.ContainsKey("UIS_Symbol1_Ratio") ||
				!mValuesDictionary.ContainsKey("UIS_Symbol2") ||
				!mValuesDictionary.ContainsKey("UIS_Symbol2_Ratio"))
			{
				return false;
			}
			
			oSomeValueHasChanged = 
				mSymbol1 != mValuesDictionary["UIS_Symbol1"] ||
				mSymbol2 != mValuesDictionary["UIS_Symbol2"] ||
				mSymbol1Ratio != Convert.ToDecimal(mValuesDictionary["UIS_Symbol1_Ratio"]) ||
				mSymbol2Ratio != Convert.ToDecimal(mValuesDictionary["UIS_Symbol2_Ratio"]);
			
			mSymbol1 = mValuesDictionary["UIS_Symbol1"];
			mSymbol2 = mValuesDictionary["UIS_Symbol2"];
			mSymbol1Ratio = Convert.ToDecimal(mValuesDictionary["UIS_Symbol1_Ratio"]);
			mSymbol2Ratio = Convert.ToDecimal(mValuesDictionary["UIS_Symbol2_Ratio"]);
			
			return true;
        }
    }
}
using QuantConnect.Data.Market;
using System;
using System.Collections.Generic;
using System.Linq;

namespace QuantConnect
{
    /// <summary>
    /// 
    /// 
	/// 
    /// </summary>
    public class GLDUSD : SubAlgorithm
    {
    	// Strategy parameters
        private string mSymbol1 = 					"GLD";
        private string mSymbol2 = 					"EUO";
        private string mSymbol3 = 					"CROC";
        private string mSymbol4 = 					"YCS";
        private int mMinimumRebalancePeriod = 		1;
        private int mSharpeLookback = 				30; //30
        private decimal mSharpeVolatilityFactor = 	2.0m; //1.0 or 2.0
        private decimal SharpeThresholdForCash =	0; // Threshold for max sharpe ratio under which the algo will go 50% cash. Needs to be tuned when changes to volatility factor are made.
        
        private SharpeRatioCalculator mMaxSharpeCombination;
        private int mDaysCounter = 0;
        private List<SharpeRatioCalculator> mSrcList;
        private decimal mLastRatio1 = 0;
        private decimal mLastRatio2 = 0;
        private decimal mLastRatio3 = 0;
        private decimal mLastRatio4 = 0;
		
        DateTime mLastHistoryCallsDate = DateTime.MinValue;
        List<TradeBar> mTradeBarHistorySymbol1;
        List<TradeBar> mTradeBarHistorySymbol2;
        List<TradeBar> mTradeBarHistorySymbol3;
        List<TradeBar> mTradeBarHistorySymbol4;
		public GLDUSD(PortfolioOfStrategies iAlgorithm, Resolution iResolution, decimal iAllocationRatio, int iStartYear, bool iRebalanceOnLaunch) : base(iAlgorithm, iResolution, iAllocationRatio, iStartYear, iRebalanceOnLaunch)
		{
			if (LiveMode)
			{
				mDataFeedFrequency = "Minute";
			}
			else
			{
				mDataFeedFrequency = "Monthly";
			}
			mRebalanceFrequency = "Monthly";
			mName = "GLDUSD";
		}
		
        public override void Initialize_Specific()
        {
        	if (EnableLogs)
        	{
	        	Log("BRS Strategy: Backtesting with following parameters:");
	        	Log("\tSymbol1                    >> " + mSymbol1);
		        Log("\tSymbol2                    >> " + mSymbol2);
		        Log("\tSymbol3                    >> " + mSymbol3);
		        Log("\tSymbol4                    >> " + mSymbol4);
		        Log("\tMinimum Rebalance Period   >> " + mMinimumRebalancePeriod);
		        Log("\tStart year                 >> " + mStartYear);
		        Log("\tSharpe lookback            >> " + mSharpeLookback);
		        Log("\tSharpe volatility factor   >> " + mSharpeVolatilityFactor);
        	}
	        
            AddSecurity(SecurityType.Equity, mSymbol1, mResolution, true, 3, false);
            AddSecurity(SecurityType.Equity, mSymbol2, mResolution, true, 3, false);
	        AddSecurity(SecurityType.Equity, mSymbol3, mResolution, true, 3, false);
            AddSecurity(SecurityType.Equity, mSymbol4, mResolution, true, 3, false);
            
            mTradeBarHistorySymbol1 = new List<TradeBar>();
            mTradeBarHistorySymbol2 = new List<TradeBar>();
            mTradeBarHistorySymbol3 = new List<TradeBar>();
			mTradeBarHistorySymbol4 = new List<TradeBar>();
	        
	        RecalculateSharpeRatios(mSharpeLookback, mSharpeVolatilityFactor, ref mSrcList);
        }

        public override void OnData_Specific(TradeBars data)
        {
            mDaysCounter = mDaysCounter - 1;
            
            RecalculateSharpeRatios(mSharpeLookback, mSharpeVolatilityFactor, ref mSrcList);
            
            decimal wRatio1 = 0.0m;
            decimal wRatio2 = 0.0m;
            decimal wRatio3 = 0.0m;
            decimal wRatio4 = 0.0m;
            
            if (mSrcList[0].IsReady)
            {
            	mMaxSharpeCombination = mSrcList.Select( (value, index) => new { Value = value, Index = index } ).Aggregate( (a, b) => (a.Value > b.Value) ? a : b ).Value;
            	// If the maximum sharpe ratio combination yields a sharpe ratio below SharpeThresholdForCash, then reduce ratios by 50% and invest 50% in cash
            	if (mMaxSharpeCombination < SharpeThresholdForCash)
            	{
            		for (int i=0; i<mMaxSharpeCombination.mSymbolsRatios.Count(); i++)
            		{
            			mMaxSharpeCombination.mSymbolsRatios[i] = mMaxSharpeCombination.mSymbolsRatios[i] / 2;
            		}
            	}
            	wRatio1 = mMaxSharpeCombination.mSymbolsRatios[0];
            	wRatio2 = mMaxSharpeCombination.mSymbolsRatios[1];
            	wRatio3 = mMaxSharpeCombination.mSymbolsRatios[2];
            	wRatio4 = mMaxSharpeCombination.mSymbolsRatios[3];
            }
			
            if (mFirstPass == true || mDaysCounter <= 0 || mLastRatio1 != wRatio1 || mLastRatio2 != wRatio2 || mLastRatio3 != wRatio3 || mLastRatio4 != wRatio4)
            {
            	mDaysCounter = mMinimumRebalancePeriod;
            	
            	if (EnableLogs)
            	{
            		Log(" ");
	            	Log("Rebalancing:");
            	}
            	
	            if (mSrcList[0].IsReady)
	            {
	            	mMaxSharpeCombination = mSrcList.Select( (value, index) => new { Value = value, Index = index } ).Aggregate( (a, b) => (a.Value > b.Value) ? a : b ).Value;
					
	                if (EnableLogs) Log("     Max Sharpe Combination >> " +
						mSymbol1 + " " + (mMaxSharpeCombination.mSymbolsRatios[0] * 100).ToString ("#.#") + "%,  " + 
						mSymbol2 + " " + (mMaxSharpeCombination.mSymbolsRatios[1] * 100).ToString ("#.#") + "%,  " +
						mSymbol3 + " " + (mMaxSharpeCombination.mSymbolsRatios[2] * 100).ToString ("#.#") + "%,  " +
						mSymbol4 + " " + (mMaxSharpeCombination.mSymbolsRatios[3] * 100).ToString ("#.#") + "%.");
		
	                if (IsTimeToRebalance())
	                {
						Trade(data, 
	                        mSymbol1, mMaxSharpeCombination.mSymbolsRatios[0], 
	                        mSymbol2, mMaxSharpeCombination.mSymbolsRatios[1], 
	                        mSymbol3, mMaxSharpeCombination.mSymbolsRatios[2], 
	                        mSymbol4, mMaxSharpeCombination.mSymbolsRatios[3]);
	                }
	            }
	            else
	            {
					if (EnableLogs) Log("     Sharpe not ready       >> " + 
						mSymbol1 + " 50%,  " + 
						mSymbol2 + " 50%,  " + 
						mSymbol3 + " 0%,  " + 
						mSymbol4 + " 0%.");

	                if (IsTimeToRebalance())
	                {
						// If sharpe ratio not ready yet, use a 50%-50% split
						Trade(data, 
	                    mSymbol1, 0.5m, 
	                    mSymbol2, 0.5m, 
	                    mSymbol3, 0.0m, 
	                    mSymbol4, 0.0m);
	                }
	            }
	            
	            mLastAllocationAmount = mAllocationAmount;
	            mLastRatio1 = wRatio1;
            }

            decimal wSymbol1Percentage;
            decimal wSymbol2Percentage;
            decimal wSymbol3Percentage;
            decimal wSymbol4Percentage;
            
            if (mSrcList[0].IsReady && mMaxSharpeCombination != null)
            {
            	wSymbol1Percentage = mMaxSharpeCombination.mSymbolsRatios[0] * 100;
            	wSymbol2Percentage = mMaxSharpeCombination.mSymbolsRatios[1] * 100;
            	wSymbol3Percentage = mMaxSharpeCombination.mSymbolsRatios[2] * 100;
            	wSymbol4Percentage = mMaxSharpeCombination.mSymbolsRatios[3] * 100;
            }
            else
            {
            	wSymbol1Percentage = 50;
            	wSymbol2Percentage = 50;
            	wSymbol3Percentage = 0;
            	wSymbol4Percentage = 0;
            }

            Plot("GLDUSD Assets Split", mSymbol1 + " (%)", wSymbol1Percentage);
            Plot("GLDUSD Assets Split", mSymbol2 + " (%)", wSymbol2Percentage);
            Plot("GLDUSD Assets Split", mSymbol3 + " (%)", wSymbol3Percentage);
            Plot("GLDUSD Assets Split", mSymbol4 + " (%)", wSymbol4Percentage);
        }
        
        protected override bool IsDataValid(TradeBars iData)
        {
        	bool wValid = true;
        	
        	wValid &= iData.ContainsKey(mSymbol1);
        	wValid &= iData.ContainsKey(mSymbol2);
			wValid &= iData.ContainsKey(mSymbol3);
			wValid &= iData.ContainsKey(mSymbol4);
			
			return wValid;
        }
        
        private void RecalculateSharpeRatios(int iLookback, decimal iVolatilityFactor, ref List<SharpeRatioCalculator> iSrcList)
        {
        	iSrcList = new List<SharpeRatioCalculator>();
	        
	        int granularity = 15;
	        for (int i=1; i<4; i++)
	        {
        		for (int j = 0; j <= granularity; j++)
        		{
        			List<decimal> wSymbolsRatios = new List<decimal> {0.0m,0.0m,0.0m,0.0m};
        			wSymbolsRatios[0] = 1/(decimal)granularity * j;
        			wSymbolsRatios[i] = 1.0m - (1/(decimal)granularity * j);
        			iSrcList.Add(SRC(wSymbolsRatios,iLookback,iVolatilityFactor));
        		}
        	}

	        // get the last 100 daily bars, once a day
            if (mAlgorithm.Time.Date > mLastHistoryCallsDate.Date)
            {
                mLastHistoryCallsDate = mAlgorithm.Time;
                mTradeBarHistorySymbol1 = History(mSymbol1, 100, Resolution.Daily).ToList();
                mTradeBarHistorySymbol2 = History(mSymbol2, 100, Resolution.Daily).ToList();
                mTradeBarHistorySymbol3 = History(mSymbol3, 100, Resolution.Daily).ToList();
				mTradeBarHistorySymbol4 = History(mSymbol4, 100, Resolution.Daily).ToList();
            }

            for (int i = 0; i < mTradeBarHistorySymbol1.Count(); i++)
            {
            	for (int j = 0; j < iSrcList.Count; j++)
		        {
		        	List<TradeBar> wData = new List<TradeBar>();
		        	wData.Add(mTradeBarHistorySymbol1[i]);
		        	wData.Add(mTradeBarHistorySymbol2[i]);
		        	wData.Add(mTradeBarHistorySymbol3[i]);
		        	wData.Add(mTradeBarHistorySymbol4[i]);
		            iSrcList[j].AddObservation(wData);
		        }
            }
        }
    }
}
using QuantConnect.Data.Market;
using System;
using System.Collections.Generic;
using System.Linq;

namespace QuantConnect
{
    /// <summary>
    /// 
    /// Maximum yield rotation strategy (MYRS) as described here: https://seekingalpha.com/article/1698412-how-to-build-an-etf-rotation-strategy-with-50-percent-annualized-returns
	/// 
    /// </summary>
    public class MYRS : SubAlgorithm
    {
    	// Strategy parameters
        private string mSymbol1 = 					"ZIV";
        private string mSymbol2 = 					"MDY";
        private string mSymbol3 = 					"EDV";
        private string mSymbol4 = 					"SHY";
        private int mMinimumRebalancePeriod = 		1;
        private int mSharpeLookback = 				63;
        private decimal mSharpeVolatilityFactor = 	0.0m;
        
        private SharpeRatioCalculator mMaxSharpeCombination;
        private List<SharpeRatioCalculator> mSrcList;
        private decimal mLastRatio1 = 0;
        private decimal mLastRatio2 = 0;
        private decimal mLastRatio3 = 0;
        private decimal mLastRatio4 = 0;
		
        DateTime mLastHistoryCallsDate = DateTime.MinValue;
        List<TradeBar> mTradeBarHistorySymbol1;
        List<TradeBar> mTradeBarHistorySymbol2;
        List<TradeBar> mTradeBarHistorySymbol3;
        List<TradeBar> mTradeBarHistorySymbol4;
		
		public MYRS(PortfolioOfStrategies iAlgorithm, Resolution iResolution, decimal iAllocationRatio, int iStartYear, bool iRebalanceOnLaunch) : base(iAlgorithm, iResolution, iAllocationRatio, iStartYear, iRebalanceOnLaunch)
		{
			if (LiveMode)
			{
				mDataFeedFrequency = "Minute";
			}
			else
			{
				mDataFeedFrequency = "Weekly";
			}
			mRebalanceFrequency = "Weekly";
			mName = "MYRS";
		}
		
        public override void Initialize_Specific()
        {
        	if (EnableLogs)
        	{
	        	Log("MYRS Strategy: Backtesting with following parameters:");
	        	Log("\tSymbol1                    >> " + mSymbol1);
		        Log("\tSymbol2                    >> " + mSymbol2);
		        Log("\tSymbol3                    >> " + mSymbol3);
		        Log("\tSymbol4                    >> " + mSymbol4);
		        Log("\tMinimum Rebalance Period   >> " + mMinimumRebalancePeriod);
		        Log("\tStart year                 >> " + mStartYear);
		        Log("\tSharpe lookback            >> " + mSharpeLookback);
		        Log("\tSharpe volatility factor   >> " + mSharpeVolatilityFactor);
        	}
	        
            AddSecurity(SecurityType.Equity, mSymbol1, mResolution, true, 3, false);
            AddSecurity(SecurityType.Equity, mSymbol2, mResolution, true, 3, false);
	        AddSecurity(SecurityType.Equity, mSymbol3, mResolution, true, 3, false);
            AddSecurity(SecurityType.Equity, mSymbol4, mResolution, true, 3, false);
            
            mTradeBarHistorySymbol1 = new List<TradeBar>();
            mTradeBarHistorySymbol2 = new List<TradeBar>();
            mTradeBarHistorySymbol3 = new List<TradeBar>();
			mTradeBarHistorySymbol4 = new List<TradeBar>();
	        
            RecalculateSharpeRatios(mSharpeLookback, mSharpeVolatilityFactor, ref mSrcList);
        }
        

        public override void OnData_Specific(TradeBars data)
        {
			
            
            RecalculateSharpeRatios(mSharpeLookback, mSharpeVolatilityFactor, ref mSrcList);
            
            decimal wRatio1 = 0.0m;
            decimal wRatio2 = 0.0m;
            decimal wRatio3 = 0.0m;
            decimal wRatio4 = 0.0m;
            
            if (mSrcList[0].IsReady)
            {
            	mMaxSharpeCombination = mSrcList.Select( (value, index) => new { Value = value, Index = index } ).Aggregate( (a, b) => (a.Value > b.Value) ? a : b ).Value;
            	wRatio1 = mMaxSharpeCombination.mSymbolsRatios[0];
            	wRatio2 = mMaxSharpeCombination.mSymbolsRatios[1];
            	wRatio3 = mMaxSharpeCombination.mSymbolsRatios[2];
            	wRatio4 = mMaxSharpeCombination.mSymbolsRatios[3];
            }

            if (mFirstPass == true || mLastRatio1 != wRatio1 || mLastRatio2 != wRatio2 || mLastRatio3 != wRatio3 || mLastRatio4 != wRatio4)
            {
            	
            	if (EnableLogs)
            	{
            		Log(" ");
	            	Log("Rebalancing:");
            	}
            	
	            if (mSrcList[0].IsReady)
	            {
	            	mMaxSharpeCombination = mSrcList.Select( (value, index) => new { Value = value, Index = index } ).Aggregate( (a, b) => (a.Value > b.Value) ? a : b ).Value;
					
	                if (EnableLogs) Log("     Max Sharpe Combination >> " +
		                mSymbol1 + " " + (mMaxSharpeCombination.mSymbolsRatios[0] * 100).ToString ("#.#") + "%,  " + 
		                mSymbol2 + " " + (mMaxSharpeCombination.mSymbolsRatios[1] * 100).ToString ("#.#") + "%,  " +
		                mSymbol3 + " " + (mMaxSharpeCombination.mSymbolsRatios[2] * 100).ToString ("#.#") + "%,  " +
		                mSymbol4 + " " + (mMaxSharpeCombination.mSymbolsRatios[3] * 100).ToString ("#.#") + "%.");
					
					if (IsTimeToRebalance())
					{
	            		Trade(data, 
	            			mSymbol1, mMaxSharpeCombination.mSymbolsRatios[0], 
	            			mSymbol2, mMaxSharpeCombination.mSymbolsRatios[1], 
	            			mSymbol3, mMaxSharpeCombination.mSymbolsRatios[2], 
	            			mSymbol4, mMaxSharpeCombination.mSymbolsRatios[3]);
					}
	            }
	            else
	            {
	            	if (EnableLogs) Log("     Sharpe not ready       >> " + 
	            		mSymbol1 + " 50%,  " + 
	            		mSymbol2 + " 50%,  " + 
	            		mSymbol3 + " 0%,  " + 
	            		mSymbol4 + " 0%.");
	                
	                if (IsTimeToRebalance())
					{
		            	// If sharpe ratio not ready yet, use a 50%-50% split between ZIV and MDY
	            		Trade(data, 
	            			mSymbol1, 0.5m, 
	            			mSymbol2, 0.5m, 
	            			mSymbol3, 0.0m, 
	            			mSymbol4, 0.0m);
					}
	            }
	            
	            mLastAllocationAmount = mAllocationAmount;
	            mLastRatio1 = wRatio1;
            }

            decimal wSymbol1Percentage;
            decimal wSymbol2Percentage;
            decimal wSymbol3Percentage;
            decimal wSymbol4Percentage;
            
            if (mSrcList[0].IsReady && mMaxSharpeCombination != null)
            {
            	wSymbol1Percentage = mMaxSharpeCombination.mSymbolsRatios[0] * 100;
            	wSymbol2Percentage = mMaxSharpeCombination.mSymbolsRatios[1] * 100;
            	wSymbol3Percentage = mMaxSharpeCombination.mSymbolsRatios[2] * 100;
            	wSymbol4Percentage = mMaxSharpeCombination.mSymbolsRatios[3] * 100;
            }
            else
            {
            	wSymbol1Percentage = 50;
            	wSymbol2Percentage = 50;
            	wSymbol3Percentage = 0;
            	wSymbol4Percentage = 0;
            }

            Plot("MYRS Assets Split", mSymbol1 + " (%)", wSymbol1Percentage);
            Plot("MYRS Assets Split", mSymbol2 + " (%)", wSymbol2Percentage);
            Plot("MYRS Assets Split", mSymbol3 + " (%)", wSymbol3Percentage);
            Plot("MYRS Assets Split", mSymbol4 + " (%)", wSymbol4Percentage);
        }
        
        protected override bool IsDataValid(TradeBars iData)
        {
        	bool wValid = true;

        	wValid &= iData.ContainsKey(mSymbol1);
        	wValid &= iData.ContainsKey(mSymbol2);
        	wValid &= iData.ContainsKey(mSymbol3);
        	wValid &= iData.ContainsKey(mSymbol4);

            return wValid;
        }
        
        private void RecalculateSharpeRatios(int iLookback, decimal iVolatilityFactor, ref List<SharpeRatioCalculator> iSrcList)
        {
            iSrcList = new List<SharpeRatioCalculator>();
	        
	        for (int i=0; i<4; i++)
	        {
    			List<decimal> wSymbolsRatios = new List<decimal> {0.0m,0.0m,0.0m,0.0m};
    			wSymbolsRatios[i] = 1.0m;
    			iSrcList.Add(SRC(wSymbolsRatios,iLookback,iVolatilityFactor));
	        }

	        // get the last 100 daily bars, once a day
            if (mAlgorithm.Time.Date > mLastHistoryCallsDate.Date)
            {
                mLastHistoryCallsDate = mAlgorithm.Time;
                mTradeBarHistorySymbol1 = History(mSymbol1, 100, Resolution.Daily).ToList();
                mTradeBarHistorySymbol2 = History(mSymbol2, 100, Resolution.Daily).ToList();
                mTradeBarHistorySymbol3 = History(mSymbol3, 100, Resolution.Daily).ToList();
				mTradeBarHistorySymbol4 = History(mSymbol4, 100, Resolution.Daily).ToList();
            }

            for (int i = 0; i < mTradeBarHistorySymbol1.Count(); i++)
            {
            	for (int j = 0; j < iSrcList.Count; j++)
		        {
		        	List<TradeBar> wData = new List<TradeBar>();
		        	wData.Add(mTradeBarHistorySymbol1[i]);
		        	wData.Add(mTradeBarHistorySymbol2[i]);
		        	wData.Add(mTradeBarHistorySymbol3[i]);
		        	wData.Add(mTradeBarHistorySymbol4[i]);
		            iSrcList[j].AddObservation(wData);
		        }
            }
        }
        
    }
}
using QuantConnect.Data.Market;
using System;
using System.Collections.Generic;
using System.Linq;

namespace QuantConnect
{
    /// <summary>
    /// 
    /// Re-coding of this python strategy: https://www.quantconnect.com/forum/discussion/3377/momentum-strategy-with-market-cap-and-ev-ebitda
	/// 
    /// </summary>
    public class FFA : SubAlgorithm
    {
    	protected int holding_months = 1;
    	protected int num_screener = 100;
        protected int num_stocks = 10;
        protected int formation_days = 200;
        protected bool lowmom = false;
        protected int month_count = 1;
        private bool mReadyToTrade = false;
		
		// rebalance the universe selection once a month
        protected bool redo_symbol_selection_flag = false;
        // make sure to run the universe selection at the start of the algorithm even it's not the month start
        protected bool first_month_symbol_selection_flag = true;
        protected int trade_flag = 0;
        protected List<Symbol> symbols = null;
        protected List<string> chosen_symbols = null;
        protected List<decimal> ratios_list = null;
        protected TradeBars mData = null;
    	
		public FFA(PortfolioOfStrategies iAlgorithm, Resolution iResolution, decimal iAllocationRatio, int iStartYear, bool iRebalanceOnLaunch) : base(iAlgorithm, iResolution, iAllocationRatio, iStartYear, iRebalanceOnLaunch)
		{
			if (LiveMode)
			{
				mDataFeedFrequency = "Minute";
			}
			else
			{
				mDataFeedFrequency = "Daily";
			}
			mRebalanceFrequency = "Monthly";
			mName = "FundamentalFactorAlgorithm";
		}
		
        public override void Initialize_Specific()
        {
        	month_count = holding_months;
        	symbols = new List<Symbol>();
        	chosen_symbols = new List<string>();
        	ratios_list = new List<decimal>();
        	AddSecurity(SecurityType.Equity, "SPY", mResolution, true, 3, false);
        	AddSecurity(SecurityType.Equity, "TLT", mResolution, true, 3, false);
        	mAlgorithm.UniverseSettings.Resolution = Resolution.Daily;
        	mAlgorithm.AddUniverse(CoarseSelectionFunction, FineSelectionFunction);
        	
        	mAlgorithm.Schedule.On(mAlgorithm.DateRules.MonthEnd("SPY"), mAlgorithm.TimeRules.At(23, 0), monthly_rebalance);
        	//mAlgorithm.Schedule.On(mAlgorithm.DateRules.MonthStart("SPY"), mAlgorithm.TimeRules.At(10, 0), rebalance);
        }

        public override void OnData_Specific(TradeBars data)
        {
        	mData = data;
            rebalance();
        }
        
        protected override bool IsDataValid(TradeBars iData)
        {
        	bool wValid = true;
        	wValid &= iData.ContainsKey("SPY");
        	wValid &= iData.ContainsKey("TLT");
        	foreach (string symbol in chosen_symbols)
        	{
        		wValid &= iData.ContainsKey(symbol);
        	}
        	wValid &= symbols.Count() > 0;
        	
			return wValid;
        }
        
        public IEnumerable<Symbol> CoarseSelectionFunction(IEnumerable<CoarseFundamental> coarse)
        {
        	if (redo_symbol_selection_flag || first_month_symbol_selection_flag)
        	{
        		List<CoarseFundamental> selected = new List<CoarseFundamental>();
        		List<Symbol> filtered = new List<Symbol>();
        		
        		foreach (CoarseFundamental x in coarse)
        		{
        			if (x.HasFundamentalData && x.Price > 5)
        			{
        				selected.Add(x);
        			}
        		}
        		
        		selected = selected.OrderByDescending(o=>o.DollarVolume).ToList();
        		
        		foreach (CoarseFundamental x in selected.Take(200))
        		{
        			filtered.Add(x.Symbol);
        		}
        		
        		return filtered;
        	}
        	else
        	{
        		return symbols;
        	}
        }
        
        public IEnumerable<Symbol> FineSelectionFunction(IEnumerable<FineFundamental> fine)
        {
        	if (redo_symbol_selection_flag || first_month_symbol_selection_flag)
        	{
        		List<FineFundamental> filtered_fine = new List<FineFundamental>();
        		List<FineFundamental> top = new List<FineFundamental>();
        		
        		try
        		{
	        		foreach (FineFundamental x in fine)
	        		{
	        			if (x.ValuationRatios.EVToEBITDA > 0 && 
	        				x.EarningReports.BasicAverageShares.ThreeMonths > 0 &&
	        				x.EarningReports.BasicAverageShares.ThreeMonths * (x.EarningReports.BasicEPS.TwelveMonths*x.ValuationRatios.PERatio) > 2000000000)
	        			{
	        				filtered_fine.Add(x);
	        			}
	        		}
        		}
	        	catch (Exception e)
	        	{
	        		filtered_fine.Clear();
	        		foreach (FineFundamental x in fine)
	        		{
	        			if (x.ValuationRatios.EVToEBITDA > 0 && 
	        				x.EarningReports.BasicAverageShares.ThreeMonths > 0)
	        			{
	        				filtered_fine.Add(x);
	        			}
	        		}
	        	}
	        	
	        	top = filtered_fine.OrderByDescending(o=>o.ValuationRatios.EVToEBITDA).ToList().Take(num_screener).ToList();
	        	symbols.Clear();
	        	
	        	foreach (FineFundamental x in top)
	        	{
	        		symbols.Add(x.Symbol);
	        	}
	        	
	        	redo_symbol_selection_flag = false;
	        	if(symbols.Count() > 0)
	        	{
	        		first_month_symbol_selection_flag = false;
	        	}
        	}
        	return symbols;
        }
        
        protected void monthly_rebalance()
        {
        	redo_symbol_selection_flag = true;
        }
        
        
        protected void rebalance()
        {
        	if (IsTimeToRebalance() && !mKeepFeedingData)
        	{
	        	IEnumerable<TradeBar> hist = mAlgorithm.History("SPY", 120, Resolution.Daily);
	        	List<decimal> spy_hist = new List<decimal>();
	        	
	        	foreach (TradeBar tradebar in hist)
	        	{
	        		spy_hist.Add(tradebar.Close);
	        	}
	        	decimal average = spy_hist.Count > 0 ? spy_hist.Average() : 0.0m;
	        
	        	if (mData["SPY"].Price < average)
	        	{
	        		Trade(mData, "TLT", 1.0m);
	        		chosen_symbols.Clear();
	        		return;
	        	}
	        	if (symbols.Count() == 0) return;
	        	
	        	chosen_symbols = calc_return(symbols).Take(num_stocks).ToList();
	        	foreach (string symbol in chosen_symbols)
	        	{
	        		Log("rebalance: " + symbol);
	        	}
	        	decimal wRatio = 1.0m/num_stocks;
	        	ratios_list = new List<decimal>();
	        	
	        	for (int i=0; i<num_stocks; i++)
	        	{
	        		ratios_list.Add(wRatio);
	        	}
	        	
	        	foreach (string symbol in chosen_symbols)
	        	{
	        		AddSecurity(SecurityType.Equity, symbol, mResolution, true, 3, false);
	        	}
				mKeepFeedingData = true;
				mReadyToTrade = true;
        	}
        	
        	if (!IsDataValid(mData))
        	{
        		foreach (string symbol in chosen_symbols)
        		{
        			if(mData.ContainsKey(symbol))
        			{
        				Log("    - " + symbol + " ok. Price = " + mData[symbol].Close);
        			}
        			else
        			{
        				Log("    - " + symbol + " not in mData.");
        			}
        		}
        		return;
        	}
        	
        	if (mReadyToTrade) 
			{
				Trade(mData,chosen_symbols,ratios_list);
				mKeepFeedingData = false;
				mReadyToTrade = false;
			}
        }

        
        protected List<string> calc_return(List<Symbol> stocks)
        {
        	IEnumerable<Slice> hist = mAlgorithm.History(stocks, formation_days, Resolution.Daily);
	        IEnumerable<Slice> current = mAlgorithm.History(stocks, 1, Resolution.Minute);
	        Dictionary<string,List<decimal>> price = new Dictionary<string,List<decimal>>();
	        Dictionary<string,decimal> ret = new Dictionary<string,decimal>();
	     
	        foreach (Symbol symbol in stocks)
        	{
        		if (symbol.Value == "UPL") continue; // For some weird reason, symbol UPL messes up the data in backtest mode, in 2004 and 2005. So ignore this symbol.
        		price[symbol.Value] = new List<decimal>();
        		foreach(Slice slice in hist)
        		{
        			if(slice.ContainsKey(symbol))
        			{
        				price[symbol.Value].Add(slice[symbol].Close);
        			}
        		}
        		foreach(Slice slice in current)
        		{
        			if(slice.ContainsKey(symbol))
        			{
        				price[symbol.Value].Add(slice[symbol].Close);
        			}
        		}
        	}
        	int priceCount;
	        foreach (string symbol in price.Keys)
        	{
        		priceCount = price[symbol].Count;
        		ret[symbol] = (price[symbol][priceCount - 1] - price[symbol][0]) / price[symbol][0];
        	}
        	
        	var sort_return = ret.ToList();
        	if (lowmom)
        	{
        		sort_return = sort_return.OrderBy(o=>o.Value).ToList();
        	}
        	else
        	{
        		sort_return = sort_return.OrderByDescending(o=>o.Value).ToList();
        	}
        	List<string> selectedSymbols = new List<string>();
        	foreach (KeyValuePair<string,decimal> keyVal in sort_return)
        	{
        		selectedSymbols.Add(keyVal.Key);
        	}

	        return selectedSymbols;
        }
    }
}