| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% 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.Threading.Tasks;
namespace QuantConnect
{
/*
* Basic Template Algorithm
*
* The underlying QCAlgorithm class has many methods which enable you to use QuantConnect.
* We have explained some of these here, but the full base class can be found at:
* https://github.com/QuantConnect/Lean/tree/master/Algorithm
*/
public class GapOnOpen : QCAlgorithm
{
private SecurityExchange Exchange;
private Dictionary<Symbol, TradeBar> lastClose;
private GapEvaluator gapEvaluator;
public override void Initialize() {
SetStartDate(2017, 2, 1);
SetEndDate(DateTime.Now.AddDays(-1));
SetCash(25000);
gapEvaluator = new GapEvaluator(0.005m, false);
AddSecurity(SecurityType.Equity, "SPY");
// S&P500 simulation
//AddUniverse(coarse => (from c in coarse orderby c.DollarVolume descending select c.Symbol).Take(500));
AddUniverse(coarse => (from c in coarse orderby c.DollarVolume descending select c.Symbol).Take(150));
Exchange = Securities["SPY"].Exchange;
Debug(Exchange.Hours.MarketHours[DayOfWeek.Monday].Segments.First().Start.ToString());
Schedule.On(DateRules.EveryDay(), TimeRules.BeforeMarketClose(Symbol("SPY")), AtMarketClose);
Schedule.On(DateRules.EveryDay(), TimeRules.AfterMarketOpen(Symbol("SPY"), 61), AfterMarketOpen);
}
private void AtMarketClose() {
var lastCandles = History(TimeSpan.FromHours(1), Resolution.Hour).ToArray();
lastClose = new Dictionary<Symbol, TradeBar>();
Parallel.Invoke(GC.Collect);
if(!lastCandles.Any()) return;
var slice = lastCandles.First();
foreach(var bar in slice.Bars) {
if(!lastClose.ContainsKey(bar.Key)) {
lastClose.Add(bar.Key, bar.Value);
}
}
}
private void AfterMarketOpen() {
if(lastClose == null) return;
var history = History(TimeSpan.FromHours(1), Resolution.Hour).ToArray();
if(!history.Any()) return;
var newCandles = history.First();
foreach(var candle in newCandles.Bars) {
if(!lastClose.ContainsKey(candle.Key)) {
//Debug($"Key {candle.Key.Value} not contained");
continue;
}
var oldCandle = lastClose[candle.Key];
var gapQuality = 0m;
var gapDirection = gapEvaluator.EvaluateGap(oldCandle, candle.Value, out gapQuality);
if(gapDirection != GapType.None) {
Debug($"{candle.Value.Time} => Gap found for Symbol {candle.Key.Value}: {gapDirection}");
}
}
}
public override void OnData(Slice data) {
}
}
}namespace QuantConnect {
public enum GapType {
None,
Up,
Down
}
public class GapEvaluator {
public decimal GapThreshold { get; set; }
public bool AccountHighLowDifference { get; set; }
public GapEvaluator(decimal gapThreshold, bool accountHighLowDifference) {
GapThreshold = gapThreshold;
AccountHighLowDifference = accountHighLowDifference;
}
public GapType EvaluateGap(TradeBar older, TradeBar newer, out decimal quality) {
var gapDistance = (newer.Open - older.Close) / older.Close;
if(Math.Abs(gapDistance) < GapThreshold) {
quality = 0;
return GapType.None;
}
var gapType = gapDistance < 0 ? GapType.Down : GapType.Up;
decimal highLowDistance = 0;
if(gapType == GapType.Up) {
highLowDistance = (newer.Low - older.High) / older.High;
} else {
highLowDistance = (older.Low - newer.High) / newer.High;
}
quality = gapDistance + (AccountHighLowDifference ? highLowDistance : 0);
return gapType;
}
}
}