Overall Statistics
Total Trades
1
Average Win
0%
Average Loss
0%
Compounding Annual Return
1.396%
Drawdown
0.000%
Expectancy
0
Net Profit
0.120%
Sharpe Ratio
7.726
Probabilistic Sharpe Ratio
96.622%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0.006
Beta
0.008
Annual Standard Deviation
0.002
Annual Variance
0
Information Ratio
-5.383
Tracking Error
0.157
Treynor Ratio
1.584
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
        };

        OrderTicket _order = null;
        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 = "EEM";
            SetStartDate(2020, 9, 25);
            SetEndDate(DateTime.Now.Date.AddDays(-1));
            SetCash(25000);
            SetBrokerageModel(BrokerageName.Alpaca, AccountType.Cash);
            
            AddSecurity(SecurityType.Equity, symbol, Resolution.Minute);
            history = new RollingWindow<TradeBar>(rollingWindowSize);
            var consolidator = new TradeBarConsolidator(barPeriod);
            consolidator.DataConsolidated += OnDataConsolidated;
            SubscriptionManager.AddConsolidator(symbol, consolidator);
        }


        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))
                    {
                        
                        _order = LimitOrder(symbol, 8, (Securities[symbol].Price * 1.001m));
                        //StopLimitOrder(symbol, -8, (Securities[symbol].Price * .9968m), (Securities[symbol].Price * .9962m));
                    	
                    }

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

                //Sell any holdings before market close.
                var oneBeforeClose = marketClose.AddMinutes(-1);
                if (Time.Hour == 15 && Time.Minute == 59)
                {
                    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;
        }

        
        public override void OnOrderEvent(OrderEvent orderEvent) 
        {
        	Debug("OnOrderEvent");
        	if (orderEvent.Status == OrderStatus.Filled 
        		&& _order != null
        		&& orderEvent.OrderId == _order.OrderId) 
        	{
        		StopMarketOrder(symbol, -8, (Securities[orderEvent.Symbol].Price * .9968m));
        		LimitOrder(symbol, -8, (Securities[orderEvent.Symbol].Price * 1.011m));
        		Log("Stop Limit Order submitted");
        	}
        }
    }
}