namespace QuantConnect
{
public class EmaCrossesAlgorithm : QCAlgorithm
{
private const string Market = "fxcm";
private const int DefaultQuantity = 25000;
private Symbol _symbol = QuantConnect.Symbol.Create("EURUSD", SecurityType.Forex, Market);
private ExponentialMovingAverage _emaFast;
private ExponentialMovingAverage _emaSlow;
private RollingWindow<decimal> _emaFastHistory = new RollingWindow<decimal>(2);
private RollingWindow<decimal> _emaSlowHistory = new RollingWindow<decimal>(2);
public override void Initialize()
{
SetStartDate(2015, 1, 1);
SetEndDate(2015, 12, 31);
SetCash(10000);
SetBenchmark(_symbol);
AddForex(_symbol, Resolution.Hour, Market);
_emaFast = EMA(_symbol, 5);
_emaSlow = EMA(_symbol, 9);
}
public override void OnData(Slice data)
{
// Add ema values to rolling windows, so we can access previous ema values
_emaFastHistory.Add(_emaFast);
_emaSlowHistory.Add(_emaSlow);
if (!_emaSlow.IsReady) return;
var bar = data[_symbol] as TradeBar;
if (bar == null) return;
if (Portfolio[_symbol].IsLong)
{
// Long exit: EmaFast crosses below EmaSlow
if (_emaFastHistory.CrossBelow(_emaSlowHistory))
{
Order(_symbol, -DefaultQuantity);
}
}
else if (Portfolio[_symbol].IsShort)
{
// Short exit: EmaFast crosses above EmaSlow
if (_emaFastHistory.CrossAbove(_emaSlowHistory))
{
Order(_symbol, DefaultQuantity);
}
}
else
{
// Long entry: EmaFast crosses above EmaSlow and EmaSlow not falling
if (_emaFastHistory.CrossAbove(_emaSlowHistory) && !_emaSlowHistory.Falling())
{
Order(_symbol, DefaultQuantity);
}
// Short entry: EmaFast crosses below EmaSlow and EmaSlow not rising
if (_emaFastHistory.CrossBelow(_emaSlowHistory) && !_emaSlowHistory.Rising())
{
Order(_symbol, -DefaultQuantity);
}
}
}
}
}
namespace QuantConnect
{
public static class RollingWindowExtensions
{
public static bool CrossAbove(this RollingWindow<decimal> window1, RollingWindow<decimal> window2, decimal tolerance = 0m)
{
return window1[0] > window2[0] * (1 + tolerance) && window1[1] < window2[1] * (1 - tolerance);
}
public static bool CrossBelow(this RollingWindow<decimal> window1, RollingWindow<decimal> window2, decimal tolerance = 0m)
{
return window1[0] < window2[0] * (1 - tolerance) && window1[1] > window2[1] * (1 + tolerance);
}
public static bool Rising(this RollingWindow<decimal> window, decimal tolerance = 0m)
{
return window[0] > window[1] * (1 + tolerance);
}
public static bool Falling(this RollingWindow<decimal> window, decimal tolerance = 0m)
{
return window[0] < window[1] * (1 - tolerance);
}
}
}