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