Overall Statistics
Total Trades
346
Average Win
0.80%
Average Loss
-0.32%
Compounding Annual Return
-0.340%
Drawdown
9.900%
Expectancy
-0.035
Net Profit
-2.026%
Sharpe Ratio
-0.053
Probabilistic Sharpe Ratio
0.208%
Loss Rate
72%
Win Rate
28%
Profit-Loss Ratio
2.48
Alpha
-0.001
Beta
-0.005
Annual Standard Deviation
0.038
Annual Variance
0.001
Information Ratio
-0.844
Tracking Error
0.124
Treynor Ratio
0.387
Total Fees
$0.00
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;
        		
				//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[symbolData.Symbol].EndTime, _Drawdown);
        		
        		Plot($"Portfolio Equity Curve", "Cumulative Return", _CumulativeReturn);
        		Plot($"Portfolio Equity Curve", "Drawdown", _Drawdown);
        		Plot($"Portfolio Equity Curve", "Drawdown EMA", _Drawdown_EMA);
        		Plot($"Portfolio Equity Curve", "High Watermark", _HighWatermark);
        		Plot($"Portfolio Equity Curve", "Max Drawdown", _MaxDrawdown);
 
				//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);
        		}

        	}
        }

    }
}
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;
	}

}
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;
	    	}
	    }
	}
}