Overall Statistics
Total Trades
911
Average Win
4.42%
Average Loss
-1.67%
Compounding Annual Return
629.491%
Drawdown
41.000%
Expectancy
0.562
Net Profit
4133.831%
Sharpe Ratio
5.579
Probabilistic Sharpe Ratio
98.758%
Loss Rate
57%
Win Rate
43%
Profit-Loss Ratio
2.64
Alpha
4.113
Beta
0.274
Annual Standard Deviation
0.746
Annual Variance
0.557
Information Ratio
5.233
Tracking Error
0.76
Treynor Ratio
15.174
Total Fees
$0.00
Estimated Strategy Capacity
$450000.00
Lowest Capacity Asset
ETHUSD XJ
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(239); //Adjust for desired bar size

        //Initialize
        public override void Initialize()
        {
            symbol = "ETHUSD";
            SetStartDate(2020, 1, 1);
            SetEndDate(DateTime.Now.Date.AddDays(-1));
            SetCash(25000);
            AddCrypto(symbol, Resolution.Minute);
            history = new RollingWindow<TradeBar>(rollingWindowSize);
            var consolidator = new TradeBarConsolidator(barPeriod);
            consolidator.DataConsolidated += OnDataConsolidated;
            SubscriptionManager.AddConsolidator(symbol, consolidator);
            var _ema = new SimpleMovingAverage(500);
        }


        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;
            var _ema = new ExponentialMovingAverage(5);
            var _emaa = EMA(symbol, 5, Resolution.Daily);
            //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 != previousBarTrendDirection1 && barTrendDirection != previousBarTrendDirection2))
                    {
                        Liquidate(symbol);
                        Debug("Liquidating " + holdings);
                    }

                    //Two candles treding up - Go long
                    if (barTrendDirection == TrendDirection.Up && Securities[symbol].Price > EMA(symbol, 5, Resolution.Daily))
                    {
                        Log("BUY  >> " + Securities[symbol].Price);
                        SetHoldings(symbol, 1.0);
                        Debug("Going Long " + holdings);
                    }
                    //Two candles treding down - Go short
                    else if (barTrendDirection == TrendDirection.Down)
                    {
                        Log("SHORT >> " + Securities[symbol].Price);
                        SetHoldings(symbol, -0.0);
                        Debug("Going Short " + 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;
        }

        
        
    }
}