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