Overall Statistics
using QuantConnect.Indicators.CandlestickPatterns;

namespace QuantConnect.Algorithm.CSharp
{

    public partial class TestAlgo : QCAlgorithm
    {
        //****************************************************************************************************************************************
        // INITIALIASE BLOCK
        //****************************************************************************************************************************************
        public override void Initialize()
        {
            SetStartDate(2014, 1, 1);
            SetEndDate(2019, 12, 31);
            SetAccountCurrency(_AccountCurrency);
            SetCash(_StartingCash);

            // Loop through our list of symbols and add them to our subscription manager
            foreach (var _symbol in _MySymbolList)
            {
                var _Forex = AddForex(_symbol, _Res, Market.Oanda, true, 20m);
                DataDico.Add(_symbol, new SymbolData(this, _Forex.Symbol, _Forex.BaseCurrencySymbol));
            }
            
            _Drawdown_EMA = new ExponentialMovingAverage(30);
            
            SetWarmUp(TimeSpan.FromDays(_WarmUpPeriod));
            SetBrokerageModel(BrokerageName.OandaBrokerage, AccountType.Margin);
        }
        

        //****************************************************************************************************************************************
        // ONDATA BLOCK
        //****************************************************************************************************************************************
        public override void OnData(Slice data)
        {
            //Loop through our dictionary
            foreach (var symbolData in DataDico.Values)
            {
                if(!data.ContainsKey(symbolData.Symbol)) { return; }

                //Check if algorithm is warming up and if indicators are ready, if not break
                if(IsWarmingUp) { return; }
                if(!symbolData.IsReady()) { return; }
                if(!symbolData.ConsolidatorFlag) { return; }
                symbolData.ConsolidatorFlag = false;
                
                //Update prices for dummy entry logic
                symbolData.Price_P2 = symbolData.Price_P1;
                symbolData.Price_P1 = symbolData.Price;
                symbolData.Price = data[symbolData.Symbol].Close;
 
                //Dummy entry logic / exit logic
                if (!Portfolio[symbolData.Symbol].Invested
                    && symbolData.ROC > 0.015m && symbolData.Price_P2 < symbolData.Price_P1 && symbolData.Price < symbolData.Price_P1 && symbolData.Price > symbolData.Price_P2)
                {
                    symbolData.Holding = Math.Round(_TotalEquity / symbolData.Price, 6);
                    MarketOrder(symbolData.Symbol, symbolData.Holding);
                }
                
                if(Portfolio.Invested && symbolData.Price_P2 > symbolData.Price_P1 && symbolData.Price_P1 > symbolData.Price)
                {
                    symbolData.Holding = Portfolio[symbolData.Symbol].Quantity;
                    MarketOrder(symbolData.Symbol, -symbolData.Holding);
                }

            }
            //Drawdown Calculation - Portfolio Level
            _TotalEquity_P1 =  _TotalEquity;
            _TotalEquity =  Portfolio.TotalPortfolioValue;
            _CumulativeReturn_P1 = _CumulativeReturn;
            try
                { _CumulativeReturn = (1 + _CumulativeReturn_P1) * (1 + (_TotalEquity/_TotalEquity_P1 - 1)) - 1; }
            catch (DivideByZeroException)
                { _CumulativeReturn = 0m; }
            _HighWatermark = Math.Max(_HighWatermark, _CumulativeReturn);
            _Drawdown = (1 + _CumulativeReturn) / (1 + _HighWatermark) - 1;
            _MaxDrawdown = Math.Min(_MaxDrawdown, _Drawdown);
            _Drawdown_EMA.Update(data.Time, _Drawdown);
            
            Plot($"Portfolio Equity Curve", "Cumulative Return", _CumulativeReturn);
            Plot($"Portfolio Equity Curve", "Drawdown", _Drawdown);
            Plot($"Portfolio Equity Curve", "Drawdown EMA", _Drawdown_EMA.Current.Value);
            Plot($"Portfolio Equity Curve", "High Watermark", _HighWatermark);
            Plot($"Portfolio Equity Curve", "Max Drawdown", _MaxDrawdown);
        }

    }
}
namespace QuantConnect.Algorithm.CSharp
{
	public partial class TestAlgo : QCAlgorithm
	{
		public class SymbolData
	    {	
        	//***Consolidator parameters***
			public static int barPerTimeSpan = 24;											// Number of block of data per custum TradeBar
    		public readonly TimeSpan barPeriod = TimeSpan.FromHours(barPerTimeSpan);		// Set the size of our custum TradeBar
			public QuoteBarConsolidator Consolidator;
	    	public bool ConsolidatorFlag = false;	// Flag whether a new custom TradeBar has been fully consolidated; used to prevent ONDATA block code to be executed otherwise

        	//***General***
	    	public readonly QCAlgorithm algorithm;
	        public readonly Symbol Symbol;
	        public readonly string BaseSymbol;
	        public readonly string AccountSymbol;
	        public readonly RollingWindow<IBaseDataBar> BarsWin;
    		public readonly int windowSize = 5;	
	   		public decimal Holding;
	     	public decimal Price;
	    	public decimal Price_P1;
	    	public decimal Price_P2;

        	//***Indicators***
        	public RateOfChange ROC;


	    	//***SymbolData class constructor which initializes a new instance of SymbolData***
	    	public SymbolData(QCAlgorithm algorithm, Symbol symbol, string baseSymbol)
	    	{	
	    		this.algorithm = algorithm;
	    		Symbol = symbol;
	    		BaseSymbol = baseSymbol;
	    		Consolidator = new QuoteBarConsolidator(barPeriod);
	    		BarsWin = new RollingWindow<IBaseDataBar>(windowSize);
	    		ROC = new RateOfChange(Symbol, _ROCperiod);

	    		Consolidator.DataConsolidated += (sender, baseData) =>
				{
        			var _bar = (IBaseDataBar)baseData;
        			ConsolidatorFlag = true;
        			BarsWin.Add(_bar);
        			ROC.Update(_bar.Time, _bar.Close);
				};
				
            	algorithm.SubscriptionManager.AddConsolidator(symbol, Consolidator);		// Adding this consolidator to the Subscription Manager so it gets auto updates

	    	}
	    		
	    	//***Returns true if all the data in this instance is ready***
	    	public bool IsReady()
	    	{
	    		return BarsWin.IsReady && ROC.IsReady;
	    	}
	    }
	}
}
namespace QuantConnect.Algorithm.CSharp
{
	public partial class TestAlgo : QCAlgorithm
	{
		//****************************************************************************************************************************************
		//USER VARIABLES
		//****************************************************************************************************************************************
		
		private static string _AccountCurrency = "USD";
		private static decimal _StartingCash = 100000m;
    	Resolution _Res = Resolution.Hour;		// Reference resolution for our custom TradeBar
    	private int  _WarmUpPeriod = 200;
    	public decimal _PctRisk = 0.10m;
		private decimal _StopLossPct = 0.05m;
		
		
    	//***Symbol List***
		Dictionary <string, SymbolData> DataDico = new Dictionary <string, SymbolData>();
		List <string> _MySymbolList = new List <string>
		{
			"EURUSD",
			"USDJPY",
			"GBPUSD",
			"USDCAD",
		};
		
		
	    //***Indicators***
	    public static int _ROCperiod = 30;


		//***Portfolio Variables for Drawdown calculation***
		private decimal _TotalEquity;
		private decimal _TotalEquity_P1;
		private decimal _CumulativeReturn;
		private decimal _CumulativeReturn_P1;
		private decimal _HighWatermark;
		private decimal _Drawdown;
		private ExponentialMovingAverage _Drawdown_EMA;
		private decimal _MaxDrawdown;
		private decimal _TotalEquity2;
	}

}