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; } } }