Overall Statistics
Total Trades
702
Average Win
3.30%
Average Loss
-3.02%
Compounding Annual Return
16.712%
Drawdown
57.900%
Expectancy
0.142
Net Profit
253.664%
Sharpe Ratio
0.526
Loss Rate
45%
Win Rate
55%
Profit-Loss Ratio
1.09
Alpha
0.145
Beta
0.003
Annual Standard Deviation
0.276
Annual Variance
0.076
Information Ratio
0.248
Tracking Error
0.328
Treynor Ratio
41.928
Total Fees
$1404.99
namespace QuantConnect 
{   

    public class Mundo : QCAlgorithm
    {
        List<string> _symbols = new List<string>() { "EURUSD", "GBPUSD", "AUDUSD", "NZDUSD", "USDCAD", "USDCHF" };
        
        TradeBars _bars = new TradeBars();
        private Dictionary<string, SymbolData> _symbolData = new Dictionary<string, SymbolData>();
        public readonly int RollingWindowSize = 2;
        public readonly TimeSpan BarPeriod = TimeSpan.FromDays(1);
        
        //parameters
        int _normPeriod = 40;
        int _period = 20;
        decimal _size = 0.2m;
        
        //how many symbols in portfolio
        decimal _syms = 6;
        
        //Initialize the data and resolution you require for your strategy:
        public override void Initialize() 
        {
			
            //Start and End Date range for the backtest:
            SetStartDate(2007, 4, 1);
            SetEndDate(2015, 6, 1);
            //SetEndDate(DateTime.Now.Date.AddDays(-1));
            
            //Cash allocation
            SetCash(10000);
            
            // initialize data
            foreach (var symbol in _symbols)
            {
                _symbolData.Add(symbol, new SymbolData(symbol, SecurityType.Forex, BarPeriod, RollingWindowSize));
            }
            
            foreach(var kvp in _symbolData)
            {

            	var symbolData = kvp.Value;
            	AddSecurity(symbolData.SecurityType, symbolData.Symbol, Resolution.Hour);
            
            	// define a consolidator to consolidate data for this symbol on the requested period
            	var consolidator = new TradeBarConsolidator(BarPeriod);
            
            	// define indicators
            	symbolData._sd = new StandardDeviation(_period);
            	symbolData._portsd = new StandardDeviation(_period);
				symbolData._min = new Minimum(_normPeriod);
				symbolData._max = new Maximum(_normPeriod);
            
            	//update indicators
            	consolidator.DataConsolidated += (sender, bar) =>
				{
					// 'bar' here is our newly consolidated data
                    symbolData._min.Update(bar.Time, symbolData._portfolio);
                    symbolData._max.Update(bar.Time, symbolData._portfolio);
                    symbolData._sd.Update(bar.Time, bar.Close);
                    symbolData._portsd.Update(bar.Time, symbolData._portfolio);
                    
                    // we're also going to add this bar to our rolling window so we have access to it later
                    symbolData.Bars.Add(bar);
                };
            
            // we need to add this consolidator so it gets auto updates
			SubscriptionManager.AddConsolidator(symbolData.Symbol, consolidator);
            	
            }
            	
		}

        //Data Event Handler: New data arrives here. "TradeBars" type is a dictionary of strings so you can access it by symbol.
        public void OnData(TradeBars data) 
        {   
            UpdateBars(data);
            if (_bars.Count != _symbols.Count) return;
            decimal _totalSd = 0;
            decimal _beta = 0;
            decimal _prt = 0;
            
            foreach (var _data in _symbolData.Values)
			{
            	if(!_data._sd.IsReady) return;
            	if(_data._sd != 0)
            	{
            		_totalSd += _data._sd;
            		_beta += _data._sd;
            	}
			}
            
            foreach (var _data in _symbolData.Values)
			{	
            	
            	//make portfolio with Mundo index beta weights
            	if(_beta != 0) _prt += _bars[_data.Symbol].Close*_data._sd/(_beta/_syms);
			}
			
			Plot("Cash", "prtSMAF", Portfolio.Cash);
			Plot("Portfolio curve", "prt", _prt);
			
			foreach (var _data in _symbolData.Values)
			{	
            	
            	_data._portfolio = _prt;
            	if((_data._max - _data._min) != 0) _data._norm = (_prt - _data._min)/(_data._max - _data._min);
            	//Plot("Normalized curve", "n", _data._norm);
				
				//------------------------------------------------------------------------------------------ EXITS
            	if(Portfolio[_data.Symbol].IsLong && _data._norm > 1m)
            	{
                	Liquidate();
            	}
            	
            	if(Portfolio[_data.Symbol].IsShort && _data._norm < 0m)
            	{
                	Liquidate();
            	}
            	
            	//------------------------------------------------------------------------------------------ ENTRIES
            	if(!Portfolio[_data.Symbol].Invested && _data._norm > 0 && _data._prenorm < 0
            	//&& (_bars[_data.Symbol].Time.Date.DayOfWeek == DayOfWeek.Monday
            	//|| _bars[_data.Symbol].Time.Date.DayOfWeek == DayOfWeek.Tuesday
            	)//)
            	{
                	if((_beta/_syms) != 0 && _data._portsd != 0) SetHoldings(_data.Symbol,  _size/(_data._sd/(_beta/_syms))*(1/_data._portsd));
                	//Log("Opened");
            	}
            	
            	if(!Portfolio[_data.Symbol].Invested && _data._norm < 1m && _data._prenorm > 1m
            	//&& (_bars[_data.Symbol].Time.Date.DayOfWeek == DayOfWeek.Monday
            	//|| _bars[_data.Symbol].Time.Date.DayOfWeek == DayOfWeek.Tuesday
            	)//)
            	{
                	if((_beta/_syms) != 0 && _data._portsd != 0) SetHoldings(_data.Symbol,  -_size/(_data._sd/(_beta/_syms))*(1/_data._portsd));
            	}
            	
            	//some prev value
            	_data._prenorm = _data._norm;
				
            	
			}
        
        	
        } // end ondata
    
    	
    	//Update the global "_bars" object
        private void UpdateBars(TradeBars data) 
        {
            foreach (var bar in data.Values)
            {
                if (!_bars.ContainsKey(bar.Symbol))
                {
                    _bars.Add(bar.Symbol, bar);
                }
                _bars[bar.Symbol] = bar;
            }
        }
        
        class SymbolData
		{
    		//stuff
    		public readonly string Symbol;
    		public readonly SecurityType SecurityType;
            public readonly RollingWindow<TradeBar> Bars;
            public readonly TimeSpan BarPeriod;
            
            //indcators
            public StandardDeviation _sd;
            public StandardDeviation _portsd;
            public Minimum _min;
            public Maximum _max;
    		
    		public decimal _portfolio;
    		public decimal _norm;
    		public decimal _prenorm;

		    public SymbolData(string symbol, SecurityType securityType, TimeSpan barPeriod, int windowSize) //, QCAlgorithm algorithm
    		{
        		Symbol = symbol;
        		SecurityType = securityType;
                BarPeriod = barPeriod;
                Bars = new RollingWindow<TradeBar>(windowSize);
                
        		_portfolio = new decimal();
        		_norm = new decimal();
        		_prenorm = new decimal();
    		}
    		
    		public bool IsReady
            {
                get { 
                    return Bars.IsReady
                    && _sd.IsReady
                    && _portsd.IsReady
                    && _min.IsReady
                    && _max.IsReady
                    ;}
            }

            public bool WasJustUpdated(DateTime current)
            {
                return Bars.Count > 0 && Bars[0].Time == current - BarPeriod;
            }
		}
    	
    } // close algo

	
}