Overall Statistics
Total Trades
5218
Average Win
0.59%
Average Loss
-0.26%
Compounding Annual Return
23.073%
Drawdown
46.000%
Expectancy
0.108
Net Profit
85.256%
Sharpe Ratio
0.84
Probabilistic Sharpe Ratio
31.709%
Loss Rate
66%
Win Rate
34%
Profit-Loss Ratio
2.30
Alpha
0
Beta
0
Annual Standard Deviation
0.216
Annual Variance
0.047
Information Ratio
0.84
Tracking Error
0.216
Treynor Ratio
0
Total Fees
$11218.70
Estimated Strategy Capacity
$76000000.00
Lowest Capacity Asset
ES Y4D62XFM9IPT
#region imports
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Globalization;
    using System.Drawing;
    using QuantConnect;
    using QuantConnect.Algorithm.Framework;
    using QuantConnect.Algorithm.Framework.Selection;
    using QuantConnect.Algorithm.Framework.Alphas;
    using QuantConnect.Algorithm.Framework.Portfolio;
    using QuantConnect.Algorithm.Framework.Execution;
    using QuantConnect.Algorithm.Framework.Risk;
    using QuantConnect.Parameters;
    using QuantConnect.Benchmarks;
    using QuantConnect.Brokerages;
    using QuantConnect.Util;
    using QuantConnect.Interfaces;
    using QuantConnect.Algorithm;
    using QuantConnect.Indicators;
    using QuantConnect.Data;
    using QuantConnect.Data.Consolidators;
    using QuantConnect.Data.Custom;
    using QuantConnect.DataSource;
    using QuantConnect.Data.Fundamental;
    using QuantConnect.Data.Market;
    using QuantConnect.Data.UniverseSelection;
    using QuantConnect.Notifications;
    using QuantConnect.Orders;
    using QuantConnect.Orders.Fees;
    using QuantConnect.Orders.Fills;
    using QuantConnect.Orders.Slippage;
    using QuantConnect.Scheduling;
    using QuantConnect.Securities;
    using QuantConnect.Securities.Equity;
    using QuantConnect.Securities.Future;
    using QuantConnect.Securities.Option;
    using QuantConnect.Securities.Forex;
    using QuantConnect.Securities.Crypto;
    using QuantConnect.Securities.Interfaces;
    using QuantConnect.Storage;
    using QuantConnect.Data.Custom.AlphaStreams;
    using QCAlgorithmFramework = QuantConnect.Algorithm.QCAlgorithm;
    using QCAlgorithmFrameworkBridge = QuantConnect.Algorithm.QCAlgorithm;
#endregion

namespace QuantConnect.Algorithm.CSharp
{
   
    public class FuturesAlgo: QCAlgorithm
    {      
		#region Global Vars
        private Future ContinuousContract;
        OrderTicket future_order;
        OrderTicket _stopLoss = null;   
        OrderTicket _takeProfit = null;
        private Future ContinuousContract_1;
        private Security CurrentContract;
		private Symbol CurrentContract_Symbol;
        private Security PreviousContract;
        private AverageDirectionalIndex AdxFast;
        private AverageDirectionalIndex AdxSlow;
        private AverageDirectionalIndex AdxUltra;
		private decimal Tolerance = .02m;
		private bool IsLong = false;
		private bool IsShort = false;
        private bool IsFlat = true;
        ExponentialMovingAverage _ema;
        Decimal AdxFast_Plus_1 = 0.0m; // I declared these as decimals as the adx values are also decimals and needed the same type to do math later. Not sure if we need to recast as double or floats?
        Decimal AdxFast_Minus_1 = 0.0m;
        Decimal AdxFast_Adx_1 = 0.0m;
        Decimal AdxSlow_Plus_1 = 0.0m;
        Decimal AdxSlow_Minus_1 = 0.0m;
        Decimal AdxSlow_Adx_1 = 0.0m;
        Decimal AdxUltra_Plus_1 = 0.0m;
        Decimal AdxUltra_Minus_1 = 0.0m;
        private TradeBar slowbar;
        private TradeBar fastbar;
        private TradeBarConsolidator slow_consolidator;
        private TradeBarConsolidator fast_consolidator;
        Decimal AdxSlow_Adx_Lastbar = 0.0m;
        Decimal AdxSlow_Plus_Lastbar = 0.0m;
        Decimal AdxSlow_Minus_Lastbar = 0.0m;
        Decimal AdxFast_Adx_Lastbar = 0.0m;
        Decimal AdxFast_Plus_Lastbar = 0.0m;
        Decimal AdxFast_Minus_Lastbar = 0.0m;
        Decimal AdxFast_Adx; // Added these which are the ADX indicators in addition to the +/- that you had already
        Decimal AdxSlow_Adx;
        Decimal AdxFast_Plus;
        Decimal AdxFast_Minus;
        Decimal AdxSlow_Plus;
        Decimal AdxSlow_Minus;
        Decimal AdxSlow_Plus_from_last = 0.0m;
        Decimal AdxSlow_Minus_from_last = 0.0m;
        Decimal AdxFast_Plus_from_last = 0.0m;
        Decimal AdxFast_Minus_from_last = 0.0m;
        Decimal stop_percent = 0.0m;
        Decimal take_profit = 0.0m;
        Decimal fillPrice = 0.0m;
        Decimal stop_price = 0.0m;
        Decimal limit_price = 0.0m;
        int slow_time;
        int fast_time;
        
        #endregion

        public override void Initialize()
        {
            //SetTimeZone(TimeZones.LosAngeles);
			SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin);// changed to Cash. Not sure if it mattered
            SetStartDate(2020, 01, 01);
            //SetEndDate(2022, 01 ,01);
			SetCash(100000);
            
            
            ContinuousContract = AddFuture(Futures.Indices.SP500EMini,
                fillDataForward: true,
                resolution: Resolution.Second,
                dataNormalizationMode: DataNormalizationMode.Raw,
                extendedMarketHours: true,
                dataMappingMode: DataMappingMode.OpenInterest, //changed to Open Interest as this is more indicative of when we should switch the trade to new contract than just last day
                contractDepthOffset: 0);
            //ContinuousContract.SetFilter(0,90);

            //var CurrentContract = ContinuousContract;           

            fast_time = GetParameter("Fast", 180);
            slow_time = GetParameter("Slow", 1800);
            AdxFast = ADX(ContinuousContract.Symbol, fast_time , Resolution.Second);
            AdxSlow = ADX(ContinuousContract.Symbol, slow_time , Resolution.Second);
            //AdxUltra = ADX(ContinuousContract.Symbol, 1 , Resolution.Second); // This is maybe important later. Ignore for now

            slow_consolidator = new TradeBarConsolidator(TimeSpan.FromSeconds(slow_time));
            slow_consolidator.DataConsolidated += SlowBarHandler;
            SubscriptionManager.AddConsolidator(ContinuousContract.Symbol, slow_consolidator);
            
            fast_consolidator = new TradeBarConsolidator(TimeSpan.FromSeconds(fast_time));
            fast_consolidator.DataConsolidated += FastBarHandler;
            SubscriptionManager.AddConsolidator(ContinuousContract.Symbol, fast_consolidator);
            
			SetWarmUp(AdxSlow.WarmUpPeriod);
            SetWarmup(AdxFast.WarmUpPeriod);
            //OnWarmupFinished(FastBarHandler);
        }

        public override void OnData(Slice data)
        {   
            if(!AdxSlow.IsReady || !AdxFast.IsReady)
            {
                return;
            }

            SetContract(data);

            AdxFast_Adx = AdxFast.Current.Value; 
            AdxSlow_Adx = AdxSlow.Current.Value;
            AdxFast_Plus = AdxFast.PositiveDirectionalIndex.Current.Value;
            AdxFast_Minus = AdxFast.NegativeDirectionalIndex.Current.Value;
            AdxSlow_Plus = AdxSlow.PositiveDirectionalIndex.Current.Value;
            AdxSlow_Minus = AdxSlow.NegativeDirectionalIndex.Current.Value;
            var AdxFast_Plus_Dif = AdxFast_Plus-AdxFast_Plus_1;
            var AdxFast_Minus_Dif = AdxFast_Minus-AdxFast_Minus_1;
            decimal max_dif = GetParameter("max_dif", 5.0m);
            bool dif = (Math.Abs(AdxSlow_Plus-AdxSlow_Minus)) > max_dif;
            int max_vol = GetParameter("max_vol", 15);
            int min_adx = GetParameter("min_adx", 20);
            //var AdxUltra_Plus = AdxUltra.PositiveDirectionalIndex.Current.Value;
            //var AdxUltra_Minus = AdxUltra.NegativeDirectionalIndex.Current.Value;
            //var Ultra_dif = Math.Abs(AdxUltra_Plus-AdxUltra_Minus);
            AdxSlow_Plus_from_last = AdxSlow_Plus- AdxSlow_Plus_Lastbar;
            AdxSlow_Minus_from_last = AdxSlow_Minus - AdxSlow_Minus_Lastbar;
            AdxFast_Plus_from_last = AdxFast_Plus - AdxFast_Plus_Lastbar;
            AdxFast_Minus_from_last = AdxFast_Minus - AdxFast_Minus_Lastbar;

            
            //Defining Vars like TV
            //not_first : We set the "last bar" value equal to the current at the end of a bars consolidation. So we don't want to react immediately after that. Hence we will mostly use !not_first
            bool not_first = AdxSlow_Plus != AdxSlow_Plus_Lastbar || AdxFast_Plus != AdxFast_Plus_Lastbar || AdxSlow_Minus != AdxSlow_Minus_Lastbar || AdxFast_Minus != AdxFast_Minus_Lastbar;
            // enterLong_fast: our Crossover(Plus,Minus) - As we have consolidated on the short time frame, we want to know what was below on the last consolidated bar (Plus <= Minus) 
            // and if it's currently gone up above the Minus during this bar.  
            bool enterLong_fast = AdxFast_Plus_Lastbar <= AdxFast_Minus_Lastbar && AdxFast_Plus > AdxFast_Minus; 
            //enterShort_fast: Same thing as above but inverted -Crossover(Minus,Plus)
            bool enterShort_fast = AdxFast_Minus_Lastbar <= AdxFast_Plus_Lastbar && AdxFast_Minus > AdxFast_Plus;
            //fallingLong: Here we are using a similar cross but this time we are looking at the Slow consolidator when Plus crosses under the ADX. 
            // First we check to see if the Adx was below the Plus on the last consolidated Bar
            // Then we check that the Plus is currently greater than the Adx. 
            // We also set a (currently) abritray number that the ADX has to be below. Values over 25 are seen to be trending so we give the some room to run with an ADX ~20.
            bool fallingLong = AdxSlow_Adx_Lastbar < AdxSlow_Plus_Lastbar && AdxSlow_Plus < AdxSlow_Adx && AdxSlow_Adx < 20; 
            //faningShort: Invesion of falling long. But still referencing the Slow Consolidator 
            bool fallingShort = AdxSlow_Adx_Lastbar < AdxSlow_Minus_Lastbar && AdxSlow_Minus < AdxSlow_Adx && AdxSlow_Adx < 20;
            //go_long: conditions to initiate long position. We check for the crossover from enterLong_fast and  to make sure there wasn't too much volatility between the current slow bar and the last one
            // so we don't get caught off guard in the middle of a highly volatile move
            bool go_long = enterLong_fast && AdxSlow_Plus_from_last < max_vol;
            // go_short: inverse of go_long including comparing change of previous Minus as opposed to previous Plus value on slow consolidator
            bool go_short = enterShort_fast && AdxSlow_Minus_from_last < max_vol;
            //exit_long: here we find falling long true OR we let a cross under of the Fast consolidator for Crossunder(Plus,Adx) but only if both ADX and the MINUS indicator is very high
            bool exit_long = fallingLong || (AdxFast_Adx_Lastbar < AdxFast_Plus_Lastbar && AdxFast_Plus < AdxFast_Adx && AdxFast_Adx > 35 && AdxFast_Minus > 35);
            //exit_short: inverse of exit long
            bool exit_short = fallingShort || (AdxFast_Adx_Lastbar < AdxFast_Minus_Lastbar && AdxFast_Minus < AdxFast_Adx && AdxFast_Adx > 35 && AdxFast_Plus > 35); 
            if (AdxFast_Adx_1 == 0) //we pass this to any variable of _Previous that is defined as 0 so that it skips the first loop
            {
                AdxFast_Adx_Lastbar = AdxFast_Adx;
                AdxFast_Plus_Lastbar = AdxFast_Plus;
                AdxFast_Minus_Lastbar = AdxFast_Minus;
                AdxSlow_Adx_Lastbar = AdxSlow_Adx;
                AdxSlow_Plus_Lastbar = AdxSlow_Plus;
                AdxSlow_Minus_Lastbar = AdxSlow_Minus;
                goto after_flat;
            }

            foreach (var changedEvent in data.SymbolChangedEvents.Values)
            {
                Debug($"{Time} - SymbolChanged event: {changedEvent}");
                if (Time.TimeOfDay == TimeSpan.Zero)
                {
                    continue;
                }
                throw new Exception($"{Time} unexpected symbol changed event {changedEvent}!");
            }

            if (IsFlat && AdxFast_Adx_1 != 0 && not_first)
            {
                if(go_long && !exit_long ) 
                {
                    future_order = Buy(CurrentContract_Symbol, 1);
                    fillPrice = future_order.AverageFillPrice;
                    stop_price = fillPrice - 40;
                    //limit_price = 40 + fillPrice;
                    IsFlat = false;
                    IsLong = true;
                    //goto after_trade;
                }
              
                if(go_short && !exit_short)
                {
                    future_order = Sell(CurrentContract_Symbol, 1);
                    fillPrice = future_order.AverageFillPrice;
                    stop_price = fillPrice + 40;
                    //limit_price = fillPrice - 40;
                    IsFlat = false;
                    IsShort = true;
                    //goto after_trade;
                }
            }

            if(IsLong && not_first)
            {
                if(exit_long || (AdxFast_Minus > 26 && AdxFast_Minus_from_last > 20)|| ContinuousContract.Price <= stop_price) //We close if exit_long is true, if the Minus on Fast Spikes
                {   
                    Liquidate(CurrentContract_Symbol);
                    IsFlat = true;
                    IsLong = false;
                    IsShort = false;
                    if (go_short) // we also flip to short if the situation says we should with go_short
                    {
                        future_order = Sell(CurrentContract_Symbol, 1);
                        fillPrice = future_order.AverageFillPrice;
                        stop_price = fillPrice + 40;
                        IsFlat = false;
                        IsShort = true;
                    }
                }
            }

            if(IsShort && not_first)
            {
                if(exit_short || (AdxFast_Plus > 26 && AdxFast_Plus_from_last > 20)|| ContinuousContract.Price >= stop_price)// Same as above but with the Plus on Fast Consolidator
                {
                    Liquidate(CurrentContract_Symbol);
                    IsFlat = true;
                    IsLong = false;
                    IsShort = false;
                    if (go_long)
                    {
                        future_order = Buy(CurrentContract_Symbol, 1);
                        fillPrice = future_order.AverageFillPrice;
                        stop_price = fillPrice - 40;
                        IsFlat = false;
                        IsLong = true;
                    }
                }
            }
            after_flat:

            AdxFast_Adx_1 = AdxFast_Adx; // these were 0.0 in the first pass, assuming this will update them after the first? correct me if I'm wrong. 
            AdxSlow_Adx_1 = AdxSlow_Adx;
            AdxFast_Plus_1 = AdxFast_Plus;
            AdxFast_Minus_1 = AdxFast_Minus;
            AdxSlow_Plus_1 = AdxSlow_Plus;
            AdxSlow_Minus_1 = AdxSlow_Minus;
            PreviousContract = CurrentContract;
        }
        
        private void SetContract(Slice slice)
        {
            CurrentContract = Securities[ContinuousContract.Mapped];
            CurrentContract_Symbol = CurrentContract.Symbol;
            if(PreviousContract!= null && CurrentContract != PreviousContract )
            {
                Liquidate(PreviousContract.Symbol);
                SubscriptionManager.RemoveConsolidator(PreviousContract.Symbol, fast_consolidator);
                SubscriptionManager.AddConsolidator(ContinuousContract.Symbol, fast_consolidator);
                SubscriptionManager.RemoveConsolidator(PreviousContract.Symbol, slow_consolidator);
                SubscriptionManager.AddConsolidator(ContinuousContract.Symbol, slow_consolidator);
            }
        }
        private void FastBarHandler(object sender, TradeBar consolidated)
        {
            /*if (fastbar != null)
            {
                AdxFast_Adx_Lastbar = AdxFast_Adx;
                AdxFast_Plus_Lastbar = AdxFast_Plus;
                AdxFast_Minus_Lastbar = AdxFast_Minus;
            }*/
            AdxFast_Adx_Lastbar = AdxFast_Adx;
            AdxFast_Plus_Lastbar = AdxFast_Plus;
            AdxFast_Minus_Lastbar = AdxFast_Minus;
            fastbar = consolidated;
        }
        private void SlowBarHandler(object sender, TradeBar consolidated)
        {   
            /*if (slowbar != null)
            {
                AdxSlow_Adx_Lastbar = AdxSlow_Adx;
                AdxSlow_Plus_Lastbar = AdxSlow_Plus;
                AdxSlow_Minus_Lastbar = AdxSlow_Minus;
            }*/
            AdxSlow_Adx_Lastbar = AdxSlow_Adx;
            AdxSlow_Plus_Lastbar = AdxSlow_Plus;
            AdxSlow_Minus_Lastbar = AdxSlow_Minus;
            slowbar = consolidated;
        }
        public void OnData(TradeBars bars)
        {
            // we need to declare this method
        }
        public void Update(IBaseData data)
        {

        }
      
	}
}