| Overall Statistics |
|
Total Trades 10001 Average Win 0.20% Average Loss -0.18% Compounding Annual Return 16.791% Drawdown 14.000% Expectancy 0.041 Net Profit 43.493% Sharpe Ratio 1.133 Loss Rate 50% Win Rate 50% Profit-Loss Ratio 1.07 Alpha NaN Beta NaN Annual Standard Deviation 0.147 Annual Variance 0.022 Information Ratio NaN Tracking Error NaN Treynor Ratio NaN Total Fees $10001.00 |
namespace QuantConnect
{
public class EMACrossLongAlgorithm : QCAlgorithm
{
// There's no need to create another instance of algorithm. We are already in the algorithm.
// So we create all variables we need here.
RollingWindow<TradeBar> History = new RollingWindow<TradeBar>(4);
RollingWindow<decimal> _8EMAHistory = new RollingWindow<decimal>(3);
RollingWindow<decimal> _8SMAHistory = new RollingWindow<decimal>(3);
RollingWindow<decimal> _20EMAHistory = new RollingWindow<decimal>(3);
public decimal AveragePriceSelector(BaseData data)
{
decimal emaMid = (_highEMA + _lowEMA) / 2;
return emaMid;
}
string symbol = "PCLN";
ExponentialMovingAverage _8EMA;
SimpleMovingAverage _8SMA;
ExponentialMovingAverage _20EMA;
ExponentialMovingAverage _highEMA;
ExponentialMovingAverage _lowEMA;
RateOfChange roc;
int fastMAPeriod = 8;
int slowEmaPeriod = 20;
//algorithm PnL settings
decimal targetProfit = 0.001m; // 0.1% target
decimal maximumLoss = 0.00041m; // 0.041% stop
// Initialize function ----------------------------------------------------------------------------
public override void Initialize() // backtest kickstart
{
SetStartDate(2012, 3, 12);
SetEndDate(2015, 7, 28);
SetCash(100000);
AddSecurity(SecurityType.Equity, symbol, Resolution.Minute);
var fifteenConsolidator = ResolveConsolidator(symbol, TimeSpan.FromMinutes(15));
_8EMA = new ExponentialMovingAverage(fastMAPeriod);
_8SMA = new SimpleMovingAverage(fastMAPeriod);
_20EMA = new ExponentialMovingAverage(slowEmaPeriod);
_highEMA = new ExponentialMovingAverage(14);
_lowEMA = new ExponentialMovingAverage(14);
roc = new RateOfChange(18);
RegisterIndicator(symbol, _8EMA, fifteenConsolidator, p => p.Value);
RegisterIndicator(symbol, _8SMA, fifteenConsolidator, p => p.Value);
RegisterIndicator(symbol, _20EMA, fifteenConsolidator, p => p.Value);
RegisterIndicator(symbol, _highEMA, fifteenConsolidator, Field.High);
RegisterIndicator(symbol, _lowEMA, fifteenConsolidator, Field.Low);
RegisterIndicator(symbol, roc, fifteenConsolidator, AveragePriceSelector);
fifteenConsolidator.DataConsolidated += (s, e) => OnDataFifteen((TradeBar)e); // ASK about this line and why it's like this
PlotIndicator(symbol, _8EMA);
PlotIndicator(symbol, _8SMA);
PlotIndicator(symbol, _20EMA);
}
public bool MinimumProfitAchieved
{
get { return (Portfolio.TotalUnrealizedProfit / Portfolio.Cash) >= targetProfit; }
}
public bool MaximumLossAchieved
{
get { return (Portfolio.TotalUnrealizedProfit / Portfolio.Cash) <= -maximumLoss; }
}
// 15m timeframe handler -----------------------------------------------------------------------------
private void OnDataFifteen(TradeBar consolidated) // OnData apparently not necessary, look up difference between TradeBars & TradeBar type
{
History.Add(consolidated);
_8EMAHistory.Add(_8EMA);
_8SMAHistory.Add(_8SMA);
_20EMAHistory.Add(_20EMA);
if (_8EMA.IsReady == false
|| _8SMA.IsReady == false
|| _20EMA.IsReady == false
|| History.Count < 4
|| _8EMAHistory.Count < 3
|| _8SMAHistory.Count < 3
|| _20EMAHistory.Count < 3) // important criterion
return;
decimal profit = Portfolio.TotalUnrealizedProfit;
decimal price = consolidated.Close;
decimal high = consolidated.High;
int holdings = Portfolio[symbol].Quantity;
decimal HLCavg = (consolidated.High + consolidated.Low + consolidated.Close) / 3;
decimal percentage = 0;
//Algorithm Entry Section:==========================================
//Entry Scenario Criteria ==========================================
// CM Check - Scenario 1: 8EMA Crossover 20EMA
// I replaced 'while' with 'if'. Tradebars will be coming, just check every tradebar.
if (Math.Abs(roc) > (decimal)0.0009) // Holdings will never be < 1. I think you meant 0.
{
if (holdings <= 0) // CONSOLIDATION CLAUSE CHECK
{
//Case 1: Standard EMA Crossover Quantitative Edge Trigger
if (_8EMA >= _20EMA)
{
// Most recent bar is History[0]. So make sure this is what you meant.
if (History[0].Close > History[1].Low || History[1].Close > History[2].Low)
{
if (HLCavg > History[0].Close || HLCavg > History[1].Close)
{
//percentage = 1.5m;
// Holdings should have values between -1 and 1. -- 1.5 is not correct.
// if you meant 1.5%, then use 0.015 for holdings value. But let's go full size.
percentage = 0.95m;
SetHoldings(symbol, percentage);
}
}
}
//Case 2: EMA/SMA Crossover Quantitative Edge Trigger | NEEDS REVISION
if (_8EMA < _20EMA)
{
if (_8EMA >= _8SMA &&
_8EMAHistory[0] > _8SMAHistory[0] &&
_8EMAHistory[1] > _8SMAHistory[1])
{
if (History[0].Close > History[1].Low || History[1].Close > History[2].Low)
{
if (HLCavg > History[0].Close || HLCavg > History[1].Close)
{
percentage = 0.95m;
SetHoldings(symbol, percentage);
}
}
}
}
}
}
//Algorithm Exit Section:===========================================
if (MinimumProfitAchieved)
{
//Order(symbol, -holdings);
// Just use Liquidate
// Or, equivalently SetHoldings(0). Or, close long and open short with SetHoldings(-1).
Liquidate(symbol);
}
if (MaximumLossAchieved)
{
//Order(symbol, -holdings);
Liquidate(symbol);
}
}
}
}