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