Overall Statistics
Total Trades
737
Average Win
0.13%
Average Loss
-0.08%
Compounding Annual Return
2.925%
Drawdown
10.900%
Expectancy
-0.016
Net Profit
1.176%
Sharpe Ratio
0.224
Probabilistic Sharpe Ratio
28.928%
Loss Rate
63%
Win Rate
37%
Profit-Loss Ratio
1.65
Alpha
0.039
Beta
0.017
Annual Standard Deviation
0.172
Annual Variance
0.03
Information Ratio
0.164
Tracking Error
0.463
Treynor Ratio
2.211
Total Fees
$23582.70
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Market;

namespace QuantConnect 
{   

    public class BasicTemplateAlgorithm : QCAlgorithm
    {
    	private OrderTicket EntryOrderUp1 { get; set; }

        private Func<QCAlgorithm, string, decimal, DateTime, OneCancelsOtherTicketSetUp1> OnOrderFilledEventUp1 { get; set; }
        private OneCancelsOtherTicketSetUp1 ProfitLossOrdersUp1 { get; set; }

    	public readonly TimeSpan BarPeriod1D = TimeSpan.FromMinutes(240);
        public readonly int RollingWindowSize = 3;
        public readonly Dictionary<string, SymbolData1D> Data1D = new Dictionary<string, SymbolData1D>();

        decimal UP_SL = 0;
    	decimal UP_TP1 =  0;
    	decimal UP_TP2 =  0;
    	
    	int quantity = 0;
        int quantity_SL = 0;
        int quantity_TP1 = 0;
        int quantity_TP2 = 0;
        
        OrderTicket LimitOrder_Symbol_UP_TP1 {get; set;}
        OrderTicket StopMarket_Symbol_UP_SL1 {get; set;}
        OrderTicket LimitOrder_Symbol_UP_TP2 {get; set;}
        OrderTicket StopMarket_Symbol_UP_SL2 {get; set;}

        public readonly IReadOnlyList<string> ForexSymbols = new List<string>
        {
            "EURUSD",
            "USDJPY",
            "EURGBP",
            "EURNZD",
            "EURAUD",
            "EURCHF",
            "USDCAD",
            "USDCHF",
            "AUDUSD",
            "NZDUSD",
            "GBPJPY",
            "EURJPY",
            "GBPAUD",
            "AUDJPY",
            "EURCAD",
            "AUDCAD",
            "CADJPY",
        };

        public override void Initialize() 
        {
            SetStartDate(2020,01, 1);         
            SetEndDate(DateTime.Now.Date.AddDays(-1));
            
            SetCash(2500000);
            
            SetBrokerageModel(BrokerageName.FxcmBrokerage);

            foreach (var symbol in ForexSymbols)
            {
                var forex = AddForex(symbol);
                Data1D.Add(symbol, new SymbolData1D(forex.Symbol, BarPeriod1D, RollingWindowSize));
            }

            foreach (var kvp in Data1D)
            {
                var symbolData1D = kvp.Value;
                var consolidator1D = symbolData1D.Symbol.SecurityType == SecurityType.Equity
                    ? (IDataConsolidator)new TradeBarConsolidator(BarPeriod1D)
                    : (IDataConsolidator)new QuoteBarConsolidator(BarPeriod1D);
                consolidator1D.DataConsolidated += (sender, baseData) =>
                {
                    var bar = (IBaseDataBar)baseData;
                    symbolData1D.Bars.Add(bar);
                };
                SubscriptionManager.AddConsolidator(symbolData1D.Symbol, consolidator1D);
            }
        }


        public void OnData(Slice slice) 
        {   
        	
            foreach (var symbolData1D in Data1D.Values)
            {
                if (symbolData1D.IsReady && symbolData1D.WasJustUpdated(Time))
                {
                	bool BarPrecRed = symbolData1D.Bars[1].Open - symbolData1D.Bars[1].Close > 0 ;
                	bool BarPrecGreen = symbolData1D.Bars[1].Close - symbolData1D.Bars[1].Open > 0 ;
                	bool BarCurrentGreen = symbolData1D.Bars[0].Close - symbolData1D.Bars[0].Open > 0 ;
                	
                	bool Signal_Condition_Up =	BarPrecRed && BarCurrentGreen &&
                								((symbolData1D.Bars[1].Open - symbolData1D.Bars[1].Close) > symbolData1D.Bars[1].Open * 0.001m) &&
                								((symbolData1D.Bars[0].Close - symbolData1D.Bars[0].Open) * 3 < (symbolData1D.Bars[1].Open - symbolData1D.Bars[1].Close))
                								;

                	UP_SL =  (symbolData1D.Bars[0].Close - symbolData1D.Bars[0].Low) ;
		        	UP_TP1 =  (symbolData1D.Bars[0].Close - symbolData1D.Bars[0].Low) ;
		        	UP_TP2 =  ((symbolData1D.Bars[0].Close - symbolData1D.Bars[0].Low) * 2) ;

		        	
		        	quantity = ((int)Math.Floor(Portfolio.Cash) + (int)Math.Floor(Portfolio.TotalProfit)) / 2;
		            quantity_SL = quantity;
		            quantity_TP1 = (int)Math.Floor(quantity * 0.5m);
		            quantity_TP2 = (int)Math.Floor(quantity_TP1 * 1m);


		            if (Signal_Condition_Up && EntryOrderUp1 == null)
		            {
		                this.OnOrderFilledEventUp1 = (algo1, symbol, filledPrice, dt) =>
			            {
			            	return new OneCancelsOtherTicketSetUp1(
			            		LimitOrder_Symbol_UP_TP1 = algo1.LimitOrder(symbolData1D.Symbol, -quantity_TP1, filledPrice + UP_TP1, "TP1"),
								StopMarket_Symbol_UP_SL1 = algo1.StopMarketOrder(symbolData1D.Symbol, -quantity_TP1, filledPrice - UP_SL, "SL1"),
								
								LimitOrder_Symbol_UP_TP2 = algo1.LimitOrder(symbolData1D.Symbol, -quantity_TP2, filledPrice + UP_TP2, "TP2"),
								StopMarket_Symbol_UP_SL2 = algo1.StopMarketOrder(symbolData1D.Symbol, -quantity_TP2, filledPrice - UP_SL, "SL2"));
			             };
					     this.EntryOrderUp1 = MarketOrder(symbolData1D.Symbol, quantity_TP1, false, "Entry_TP1 : " + Time);
					     this.EntryOrderUp1 = MarketOrder(symbolData1D.Symbol, quantity_TP2, false, "Entry_TP2 : " + Time);
		            }
		        }	
            }
        }

        public override void OnOrderEvent(OrderEvent orderEvent)
        {
        	var order = Transactions.GetOrderById(orderEvent.OrderId);
        	
            if (EntryOrderUp1 != null)
            {
                this.EntryOrderUp1 = null;
            }

			if (orderEvent.Status == OrderStatus.Filled || orderEvent.Status == OrderStatus.PartiallyFilled)
            {
            if (this.OnOrderFilledEventUp1 != null)
            {
                this.ProfitLossOrdersUp1 = OnOrderFilledEventUp1(this, orderEvent.Symbol, orderEvent.FillPrice, orderEvent.UtcTime);
                OnOrderFilledEventUp1 = null;
            } 
	            else if (this.ProfitLossOrdersUp1 != null)
	            {
	            if (order.Type == OrderType.StopMarket)
	            {
	                this.ProfitLossOrdersUp1.Filled();
	                this.ProfitLossOrdersUp1 = null;
	            }
	            }
            }

			if (orderEvent.Status == OrderStatus.Filled && this.ProfitLossOrdersUp1 != null)
			{
	            if ((order.Tag.Equals("TP1")))
				{
		            StopMarket_Symbol_UP_SL1.Cancel();
	            }
	            
	            if ((order.Tag.Equals("TP2")))
				{
		            StopMarket_Symbol_UP_SL2.Cancel();
		            ////Don't forget to put this ProfitLossOrdersUp1 reset to null here, in the last level of Take-Profit.
		            this.ProfitLossOrdersUp1 = null;
	            }
			}
        }        
    }
    
    public class SymbolData1D
    {
        public readonly Symbol Symbol;
        public readonly RollingWindow<IBaseDataBar> Bars;
        public readonly TimeSpan BarPeriod1D;

        public SymbolData1D(Symbol symbol, TimeSpan barPeriod1D, int windowSize)
        {
            Symbol = symbol;
            BarPeriod1D = barPeriod1D;
            Bars = new RollingWindow<IBaseDataBar>(windowSize);
        }

        public bool IsReady
        {
            get { return Bars.IsReady;}
        }

        public bool WasJustUpdated(DateTime current)
        {
            return Bars.Count > 0 && Bars[0].Time == current - BarPeriod1D;
        }
    }
}
namespace QuantConnect 
{
    public class OneCancelsOtherTicketSetUp1
    {
        public OneCancelsOtherTicketSetUp1(params OrderTicket[] orderTicketsUp1)
        {
            this.OrderTicketsUp1 = orderTicketsUp1;
        }

        private OrderTicket[] OrderTicketsUp1 { get; set; }

        public void Filled()
        {
            // Cancel all the outstanding tickets.
            foreach (var orderTicket in this.OrderTicketsUp1)
            {
                if (orderTicket.Status == OrderStatus.Submitted)
                {
                    orderTicket.Cancel();
                }
            }
    	}
    }
}