Overall Statistics
Total Trades
2
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$0.00
using System;
using System.Collections;
using System.Collections.Generic; 
using QuantConnect.Securities;  
using QuantConnect.Models;   

namespace QuantConnect 
{   
    // Simple Heikin-Ashi adjustable candlestick trading algorithm.
    // Exit point is two opposing trend bars, entry is two consecutive bars in same direction.
    // Only trades in exchange opening hours and liquidates all before closing.
    // See: http://www.investopedia.com/articles/technical/04/092204.asp
    // Like other moving averages. This is a lagging indicator, so the chop will eliminate any gains if used by it self. 
    // However it can be used in conjunction with other indicators to spot trends.
    public class SimpleHeikinAshi : QCAlgorithm
    {
		public enum TrendDirection
        {
            Up,
            Down
        };

        string symbol;
        int rollingWindowSize = 3;
        RollingWindow<TradeBar> history = null;
        TimeSpan barPeriod = TimeSpan.FromMinutes(30); //Adjust for desired bar size

        //Initialize
        public override void Initialize()
        {
            symbol = "QQQ";
            SetStartDate(2020, 9, 24);
            SetEndDate(DateTime.Now.Date.AddDays(-1));
            SetCash(25000);
            AddSecurity(SecurityType.Equity, symbol, Resolution.Minute);
            history = new RollingWindow<TradeBar>(rollingWindowSize);
            var consolidator = new TradeBarConsolidator(barPeriod);
            consolidator.DataConsolidated += OnDataConsolidated;
            SubscriptionManager.AddConsolidator(symbol, consolidator);
            
            SetBrokerageModel(BrokerageName.Alpaca);
        }


        public void OnDataConsolidated(object sender, TradeBar data)
        {
            var instrument = Securities[symbol];
            var exchange = instrument.Exchange;
            var marketClose = exchange.Hours.GetNextMarketClose(instrument.LocalTime, false);
            var marketOpen = exchange.Hours.GetNextMarketOpen(instrument.LocalTime.AddDays(-1), false);
            var tradeStartAfterOpen = marketOpen.AddMinutes(1);

            TradeBar thisHeikinAshiBar;
            if (!history.Any())
                thisHeikinAshiBar = CalculateHeikinAshiBar(data, null);
            else
                thisHeikinAshiBar = CalculateHeikinAshiBar(data, history[0]);

            history.Add(thisHeikinAshiBar);

            var holdings = Securities[symbol].Holdings.Quantity;

            //Establish first three bars before trading
            if (history.IsReady)
            {
                TrendDirection barTrendDirection = getTrendDirection(thisHeikinAshiBar);
                TrendDirection previousBarTrendDirection1 = getTrendDirection(history[1]);
                TrendDirection previousBarTrendDirection2 = getTrendDirection(history[2]);

                //Wait for the maket open volatility to settle before trading.
                if (exchange.ExchangeOpen && Time > tradeStartAfterOpen && Time <= marketClose)
                {
                    //Exit on one bar trend change
                    if (holdings == 0 && (barTrendDirection == TrendDirection.Up))
                    {
                        
                        LimitOrder(symbol, 1, (Securities[symbol].Price * 1.001m));
                        StopLimitOrder(symbol, -1, (Securities[symbol].Price * .9988m), (Securities[symbol].Price * .9982m));
                    	
                    }

                    //Two candles treding up - Go long
                    if (holdings != 0 && (barTrendDirection == TrendDirection.Down))
                    {
                        Transactions.CancelOpenOrders(symbol);
                        LimitOrder(symbol, -1, (Securities[symbol].Price * .998m));
                        Debug("SELLING" + holdings);
                    }
                   
                }

                //Sell any holdings before market close.
                var oneBeforeClose = marketClose.AddMinutes(-1);
                if (Time == oneBeforeClose)
                {
                    if (!Portfolio.HoldStock)
                    {
                        Liquidate(symbol);
                        history.Reset();
                    }
                }
            }
        }

        public void OnData(TradeBars data)
        { }

        //Returns a TradeBar where OHLC values are smoothed from previous bar.
        public TradeBar CalculateHeikinAshiBar(TradeBar bar, TradeBar previousHeikinAshiBar)
        {
            TradeBar result = (TradeBar)bar.Clone();

            //Average price of the current bar
            result.Close = (bar.Open + bar.High + bar.Low + bar.Close) / 4;

            //Midpoint of the previous bar
            if (previousHeikinAshiBar != null)
                result.Open = (previousHeikinAshiBar.Open + previousHeikinAshiBar.Close) / 2;
            else
                result.Open = (bar.Open + bar.Close) / 2;

            result.High = Math.Max(Math.Max(bar.High, result.Open), result.Close);
            result.Low = Math.Min(Math.Min(bar.Low, result.Open), result.Close);
            return result;
        }

        //Establishes the green/red direction of the candlestick.
        public TrendDirection getTrendDirection(TradeBar bar)
        {
            TrendDirection result = (bar.Open > bar.Close) ? TrendDirection.Down : TrendDirection.Up;

            return result;
        }

        
        
    }
}