Overall Statistics
Total Trades
967
Average Win
0.75%
Average Loss
-0.43%
Compounding Annual Return
-97.073%
Drawdown
48.900%
Expectancy
-0.149
Net Profit
-26.626%
Sharpe Ratio
-1.86
Loss Rate
69%
Win Rate
31%
Profit-Loss Ratio
1.74
Alpha
-0.819
Beta
-82.198
Annual Standard Deviation
1.113
Annual Variance
1.24
Information Ratio
-1.874
Tracking Error
1.113
Treynor Ratio
0.025
Total Fees
$0.00
/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

using System;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Orders;

namespace QuantConnect.Algorithm.CSharp
{

    public class BasicTemplateForexAlgorithm : QCAlgorithm
    {
        // Initialize variables

		private DateTime startTime = DateTime.Now;
	    private DateTime startDate = new DateTime(2018, 12, 1);
	    private DateTime endDate = new DateTime(2019, 1, 1);
	    private decimal portfolioAmount = 5000;
        public int maxLotSize = 100000;
        private static decimal maxLeverage = 50m;        // Maximum Leverage.
        private decimal leverageBuffer = 0.25m;         // Percentage of Leverage left unused.
        private decimal maxRiskPercent = 0.02m;

		readonly string[] NYPairs = new string[] {  
			"AUDCAD",
			"AUDCHF",
			"AUDNZD",
			"AUDUSD",
			"CADCHF",
			"EURAUD",
			"EURCAD",
			"EURCHF",
	   		"EURGBP",
    		"EURNZD",
			"EURUSD",
			"GBPAUD",
			"GBPCAD",
			"GBPCHF",
			"GBPNZD",
			"GBPUSD",
			"NZDCAD",
			"NZDCHF",
			"NZDUSD",
			"USDCAD",
			"USDCHF"
		};

		readonly string[] YPairs = new string[] {  
			"AUDJPY",
			"CADJPY",
			"CHFJPY",
	    	"EURJPY",
			"GBPJPY",
			"NZDJPY",
			"USDJPY"
		};

        /// This is the period of bars that will be created
        public readonly TimeSpan FourHrHA = TimeSpan.FromMinutes(240);
        public readonly TimeSpan HalfHrHA = TimeSpan.FromMinutes(30);
        public readonly decimal BrickSizeNY = 0.001m;
        public readonly decimal BrickSizeY = 0.1m;
        
        // Period of the indicators
        public readonly int ExpMovAvePd = 20;
        public readonly int fastMAPd = 15;
        public readonly int slowMAPd = 26;
        public readonly int signalPd = 3;
        
        // Direction indicators for 4Hr, 30Min and EMA (1 up, -1 down)
        public int FourHrDir = 0;
        public int HalfHrDir = 0;
        public int EMADir = 0;
        public int RenkoDir = 0;
        public int TradeDir = 0;
        

        /// This is the number of consolidated bars we'll hold in symbol data for reference
        public readonly int FourHrRollWindSize = 2;
  		public readonly int HalfHrRollWindSize = 8;
  		public readonly int RenkoRollWindSize = 5;
  
        /// Holds all of our data keyed by each symbol
        public Dictionary<string, SymbolData> Data = new Dictionary<string, SymbolData>();
		
        /// Holds all of our data keyed by each symbol
        public Dictionary<string, OrderData> orders = new Dictionary<string, OrderData>();

//        // Holds all Ticket data keyed by Order Id
		public Dictionary<int, string> Orders = new Dictionary<int, string>();


        /// Initialize the data, resolution cash, start and end dates required. All algorithms must initialized.
        public override void Initialize()
        {
            SetStartDate(startDate);  //Set Start Date
            SetEndDate(endDate);    //Set End Date
            SetCash(portfolioAmount);             //Set Strategy Cash
            
            // set the brokerage model
            SetBrokerageModel(BrokerageName.OandaBrokerage);
            
            // initialize our forex data
            foreach (var symbol in NYPairs)
            {
            	var forex = AddForex(symbol,Resolution.Second);
                Data.Add(symbol, new SymbolData(symbol, FourHrRollWindSize, HalfHrRollWindSize, BrickSizeNY, RenkoRollWindSize));
            }
            
 /*           foreach (var symbol in YPairs)
            {
            	var forex = AddForex(symbol,Resolution.Second);
            	Data.Add(symbol, new SymbolData(symbol, FourHrRollWindSize, HalfHrRollWindSize, BrickSizeY, RenkoRollWindSize));
            }
 */           
            // loop through all our symbols and request data subscriptions and initialize indicatora
            foreach(var kvp in Data)
            {
            	var symbolData = kvp.Value;
            	
            	// Add the Symbol to data subscriptions
 
            	
            	// Define conslidators for 4Hr, 30Min and Renko
            	var FourHrcons = new QuoteBarConsolidator(FourHrHA);
            	var HalfHrcons = new QuoteBarConsolidator(HalfHrHA);
            	var Renkocons = new RenkoConsolidator(symbolData.RenkoBrick);
            	
            	// Define and register indicators
            	symbolData.MACD = new MovingAverageConvergenceDivergence(symbolData.Symbol,fastMAPd,slowMAPd,signalPd,MovingAverageType.Exponential);
            	symbolData.FourHrHA = new HeikinAshi(symbolData.Symbol);
            	symbolData.HalfHrHA = new HeikinAshi(symbolData.Symbol);
            	symbolData.EMA = new ExponentialMovingAverage(symbolData.Symbol,ExpMovAvePd).Of(symbolData.HalfHrHA);
            	
//            	RegisterIndicator(symbolData.Symbol, symbolData.FourHrHA, FourHrcons);
//            	RegisterIndicator(symbolData.Symbol, symbolData.HalfHrHA, HalfHrcons);
//            	RegisterIndicator(symbolData.Symbol, symbolData.EMA, HalfHrcons);
            	RegisterIndicator(symbolData.Symbol, symbolData.MACD, Renkocons);
            	
            	// Wire up consolidators to update indicators and rolling windows
            	FourHrcons.DataConsolidated += (sender, consolidated) =>
            	{
//            		Debug(Time.ToString("u") + " Open price: " + consolidated.Open + " Close Price: " + consolidated.Close);
		        	symbolData.FourHrHA.Update(consolidated);
		        	
		        	//Add new Bar to history
		        	symbolData.FourHrBars.Add(symbolData.FourHrHA);
		        	
		        	if(symbolData.FourHrHA.Open>symbolData.FourHrHA.Close)
		        	{
		        		FourHrDir = -1; // Close Lower, Red Candle
//		        		Debug(Time.ToString("o") + " 4Hr Red");
		        	}
		        	else if(symbolData.FourHrHA.Open<symbolData.FourHrHA.Close)
		        	{
		        		FourHrDir = 1; // Close Higher, Green Candle
//		        		Debug(Time.ToString("o") + " 4Hr Green");
		        	}
            	};
            	
            	HalfHrcons.DataConsolidated += (sender, consolidated) =>
            	{
            		// Update the 30min HA bar
		        	symbolData.HalfHrHA.Update(consolidated);
//            		Debug(Time.ToString("u") + " Open price: " + symbolData.HalfHrHA.Open + " Close Price: " + symbolData.HalfHrHA.Close);
		        	
		        	//Add new Bar to history
		        	symbolData.HalfHrBars.Add(symbolData.HalfHrHA);
		        	
		        	var tradeBar = new TradeBar(symbolData.HalfHrHA.Current.EndTime, symbolData.Symbol, symbolData.HalfHrHA.Open, symbolData.HalfHrHA.High, symbolData.HalfHrHA.Low, symbolData.HalfHrHA.Close, 0);
		        	
		        	if(symbolData.HalfHrHA.Open>symbolData.HalfHrHA.Close)
		        	{
		        		HalfHrDir = -1; // Close Lower, Red Candle
//		        		Debug(Time.ToString("o") + " 30 Min Red");
		        	}
		        	else if(symbolData.HalfHrHA.Open<symbolData.HalfHrHA.Close)
		        	{
		        		HalfHrDir = 1; // Close Higher, Green Candle
//		        		Debug(Time.ToString("o") + " 30 Min Green");
		        	}
		        	
		        	// Update 30Min EMA
		        	symbolData.EMA.Update(tradeBar.Time, tradeBar.Close);
		        	
		        	// Add new EMA value to history
		        	symbolData.EMAVals.Add(symbolData.EMA);
		        	
		        	if(symbolData.EMAVals.Count > 1)
		        	{
			        	if(symbolData.EMAVals[1]>symbolData.EMAVals[0])
			        	{
			        		EMADir = -1; // EMA slope Down
//			        		Debug("30 Min EMA Slope Down.  Last EMA " + symbolData.EMAVals[1].ToString() + " Current EMA " +symbolData.EMAVals[0].ToString());
			        	}
			        	else if(symbolData.EMAVals[1]<symbolData.EMAVals[0])
			        	{
			        		EMADir = 1; // EMA slope Up
//			        		Debug("30 Min EMA Slope up.  Last EMA " + symbolData.EMAVals[1].ToString() + " Current EMA " +symbolData.EMAVals[0].ToString());
			        	}
			        	else
			        	{
			        		EMADir = 0; // EMA slope flat
//			        		Debug(" 30 Min EMA Slope flat.  Last EMA " + symbolData.EMAVals[1].ToString() + " Current EMA " +symbolData.EMAVals[0].ToString());
			        	}
		        	}
            	};
            	
            	Renkocons.DataConsolidated += OnRenkoClose;
            	
            	// we need to add this consolidator so it gets auto updates
            	SubscriptionManager.AddConsolidator(symbolData.Symbol, FourHrcons);
                SubscriptionManager.AddConsolidator(symbolData.Symbol, HalfHrcons);
                SubscriptionManager.AddConsolidator(symbolData.Symbol, Renkocons);
            }
        }
        
        /// <summary>
        /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        /// </summary>
        public void OnData(QuoteBar data)
        {
        }
        
		 public override void OnOrderEvent(OrderEvent orderEvent)
        {
        	
        }
        
		/// <summary>
        /// OnRenkoClose event what happens when each Renko Bar is done.
        /// </summary>
        public void OnRenkoClose(object sender, RenkoBar bar) 
        {
        	var symbolData = Data[bar.Symbol];
        	int Lots=0;
        	int OrderTicket;

//Debug("4Hr Direction: " + FourHrDir + "  30Min Direction: " + HalfHrDir + " EMA Direction: " + EMADir
//	+ " Renko Brick Info: Open " + bar.Open + " Close " + bar.Close + " MACD Histogram " + symbolData.MACD.Histogram);
        	// Add new Renko bar to history
        	symbolData.RenkoBars.Add(bar);
 
 			// We are in a long position and we have a Red Brick
 			if(TradeDir == 1 && bar.Open > bar.Close)
 			{
 				Liquidate(bar.Symbol);	// Liquidate Long Trade
 				TradeDir = 0;			// No Trade Direction
//Debug("Renko Brick Info: Open " + bar.Open + " Close " + bar.Close + " MACD Histogram " + symbolData.MACD.Histogram);
 			}
 			
 			// We are in a short position and we have a Green Brick
 			if(TradeDir == -1 && bar.Open < bar.Close)
 			{
 				Liquidate(bar.Symbol);	// Liquidate Short Trade
 				TradeDir = 0;			// No Trade Direction
//Debug("Renko Brick Info: Open " + bar.Open + " Close " + bar.Close + " MACD Histogram " + symbolData.MACD.Histogram);
			}
 			
        	if(FourHrDir == 1 && HalfHrDir == 1 && EMADir == 1 && 
        		bar.Open < bar.Close && symbolData.MACD.Histogram > 0 && TradeDir == 0)
        	{
        		//Enter long trade
        		Lots = CalculateLotSize(bar.Symbol);
        		OrderTicket=MarketOrder(bar.Symbol, Lots);
        		TradeDir = 1;
//Debug("4Hr Direction: " + FourHrDir + "  30Min Direction: " + HalfHrDir + " EMA Direction: " + EMADir
//	+ " Renko Brick Info: Open " + bar.Open + " Close " + bar.Close + " MACD Histogram " + symbolData.MACD.Histogram);        		
        	}
        	
        	if(FourHrDir == -1 && HalfHrDir == -1 && EMADir == -1 && 
        	bar.Open > bar.Close && symbolData.MACD.Histogram < 0  && TradeDir == 0)
        	{
        		//Enter short trade
        		Lots = -CalculateLotSize(bar.Symbol);
        		OrderTicket=MarketOrder(bar.Symbol, Lots);
        		TradeDir = -1;
//Debug("4Hr Direction: " + FourHrDir + "  30Min Direction: " + HalfHrDir + " EMA Direction: " + EMADir
//	+ " Renko Brick Info: Open " + bar.Open + " Close " + bar.Close + " MACD Histogram " + symbolData.MACD.Histogram);
        	}
        	
 //       	Debug(Time.ToString("u") + " Open price: " + bar.Open + " Close Price: " + bar.Close);
		}
		
		/// <summary>
        /// CalculateLotSize determines lot size based on risk tolerance.
        /// </summary>
        public int CalculateLotSize(string symbol)
		{
			decimal ShareSize = (maxLeverage * maxRiskPercent); // Risk percentage size calculation for lot size calc
			int quantity = (int) (Math.Floor(CalculateOrderQuantity(symbol, ShareSize)/1000))*1000;
			
//			Debug("Number of Shares " + quantity);
			
			return Math.Min(quantity,maxLotSize);
		}
		
    }
}
namespace QuantConnect {
    /// <summary>
    /// Contains data pertaining to a symbol in our algorithm
    /// </summary>
    public class OrderData
    {
        /// <summary>
        /// The Entry, Stop Loss and Target
        /// </summary>
        public decimal FirstEntry;
        public decimal SecondEntry;
        public decimal StopLoss;
        public decimal Target;

        /// <summary>
        /// The Entry, Stop and Target order numbers
        /// </summary>
        public OrderTicket FirstEntryTicket = null;
        public OrderTicket SecondEntryTicket = null;
        public OrderTicket StopLossTicket = null;
        public OrderTicket TargetTicket = null;

		//Share Size - based on portfolio size.  Used to Calculate LotSize
		public decimal ShareSize;
		
        /// <summary>
        /// The lot size for the setup
        /// </summary>
        public int FirstLotSize;
        public int SecondLotSize;

        /// <summary>
        /// Initializes a new instance of OrderData
        /// </summary>
        public OrderData(decimal shareSize)
        {
        	ShareSize = shareSize;
        }

        public OrderData(decimal firstEntry, decimal secondEntry, decimal stopLoss, decimal target)
        {
            FirstEntry = firstEntry;
            SecondEntry = secondEntry;            
            StopLoss = stopLoss;
            Target = target;
        }
    }
}
namespace QuantConnect {
    /// <summary>
    /// Contains data pertaining to a symbol in our algorithm
    /// </summary>
    public class SymbolData
    {
        /// This symbol the other data in this class is associated with
        public readonly Symbol Symbol;

        /// A rolling window of data, data needs to be pumped into Bars by using Bars.Update( tradeBar ) and
        /// can be accessed like:
        ///  mySymbolData.Bars[0] - most first recent piece of data
        ///  mySymbolData.Bars[5] - the sixth most recent piece of data (zero based indexing)
        public readonly RollingWindow<HeikinAshi> FourHrBars;
        public readonly RollingWindow<HeikinAshi> HalfHrBars;
        public readonly RollingWindow<RenkoBar> RenkoBars;
        public readonly RollingWindow<decimal> EMAVals;

        /// The period used when population the Bars rolling window.
        public readonly TimeSpan FourHrPeriod;
        public readonly TimeSpan HalfHrPeriod;
        public readonly decimal RenkoBrick;

        /// The indicators for our symbol
        public ExponentialMovingAverage EMA;
        public MovingAverageConvergenceDivergence MACD;
        public HeikinAshi FourHrHA;
        public HeikinAshi HalfHrHA;
        

        // Order information
        public OrderData Long;
        public OrderData Short;

        /// <summary>
        /// Initializes a new instance of SymbolData
        /// </summary>
        public SymbolData(Symbol symbol, int windowSize1, int windowSize2, decimal renkoSize, int windowSize3)
        {
            Symbol = symbol;
            RenkoBrick = renkoSize;
            FourHrBars = new RollingWindow<HeikinAshi>(windowSize1);
            HalfHrBars = new RollingWindow<HeikinAshi>(windowSize2);
            EMAVals = new RollingWindow<decimal>(windowSize2);
            RenkoBars = new RollingWindow<RenkoBar>(windowSize3);
        }
        
        /// <summary>
        /// Returns true if all the data in this instance is ready (indicators, rolling windows, ect...)
        /// </summary>
        public bool FourHrIsReady
        {
            get { return FourHrBars.IsReady; }
        }
        
        
        /// <summary>
        /// Returns true if all the data in this instance is ready (indicators, rolling windows, ect...)
        /// </summary>
        public bool HalfHrIsReady
        {
            get { return HalfHrBars.IsReady; }
        }
        
        
        /// <summary>
        /// Returns true if all the data in this instance is ready (indicators, rolling windows, ect...)
        /// </summary>
        public bool RenkoIsReady
        {
            get { return RenkoBars.IsReady; }
        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using QuantConnect.Securities;
using QuantConnect.Models;

namespace QuantConnect 
{
    
    /*
    *   TimeSpanConsolidator Helper Routine: Assemble generic timespan bar lengths: e.g. 10 minutes:
    *
    *   1. Setup the new Consolidator class with the timespan period:
    *   var _consolidator = new Consolidator(TimeSpan.FromMinutes(10));
    *
    *   2. Add in the data with the update routine. It will return true when bar ready
    *   if (_consolidator.Update(data["MSFT"])) {   UseBar    }
    */
    public class Consolidator 
    {
        public TradeBar resultBar;
        private TradeBar workingBar;
        private DateTime start;
        private TimeSpan period;
        
        //Result:
        public TradeBar Bar
        {
            get
            {
                return resultBar;
            }
        }
        
        //Constructor: Set the period we'd like to scan
        public Consolidator(TimeSpan span) 
        {
            this.period = span;
            this.resultBar = new TradeBar();
            this.workingBar = new TradeBar(new DateTime(), "", Decimal.Zero, Decimal.MinValue, Decimal.MaxValue, 0, 0);
        }
        
        //Submit this bar, return true if we've started a new one.
        public bool Update(TradeBar newBar)
        {
            //Intialize:
            if (start == new DateTime()) 
            {
                start = newBar.Time;
            }
            
            //While we're less than end date, keep adding to this bar:
            if (newBar.Time < (start + period))
            {
                //Building bar:
                AddToBar(newBar);
                return false;
            } 
            else 
            {
                //Completed bar: start new one:
                resultBar = workingBar;
                //Create a new bar:
                workingBar = new TradeBar(newBar.Time, newBar.Symbol, Decimal.Zero, Decimal.MinValue, Decimal.MaxValue, 0, 0);
                //Start of this bar:
                start = newBar.Time;
                AddToBar(newBar);
                return true;
            }
        }
        
        //Add to a tradebar
        private void AddToBar(TradeBar newBar)
        {
            //Add this data to working bar:
            if (workingBar.Time == new DateTime()) workingBar.Time = newBar.Time;
            if (workingBar.Symbol == "") workingBar.Symbol = newBar.Symbol;
            if (workingBar.Open == Decimal.Zero) workingBar.Open = newBar.Open;
            if (newBar.High > workingBar.High) workingBar.High = newBar.High;
            if (newBar.Low < workingBar.Low) workingBar.Low = newBar.Low;
            workingBar.Close = newBar.Close;
            workingBar.Volume = newBar.Volume;
        }
    }
}