Overall Statistics |
Total Trades 277 Average Win 0.03% Average Loss -0.01% Compounding Annual Return 230.169% Drawdown 0.500% Expectancy 0.751 Net Profit 1.539% Sharpe Ratio 11.101 Loss Rate 39% Win Rate 61% Profit-Loss Ratio 1.87 Alpha 0.073 Beta 63.418 Annual Standard Deviation 0.07 Annual Variance 0.005 Information Ratio 10.964 Tracking Error 0.069 Treynor Ratio 0.012 Total Fees $277.00 |
using System.Net.Http; using System.Text; using Newtonsoft.Json; 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 enum PointType { NA = 'N', A = 'A', C = 'C', D = 'D' } public enum PointDirection { Up = 'U', Down = 'D' } public enum PointStatus { Failed = 'F', Pending = 'P', Success = 'S', Complete = 'C' } public class Range { public TimeSpan Begin = new TimeSpan(23,59,59); public TimeSpan End = new TimeSpan(00,00,00); public decimal Low = 0xFFFFF; public decimal High = -0xFFFFF; public bool Completed = false; public Range() { Low = 0xFFFFF; High = -0xFFFFF; Completed = false; } public int Duration() { return End.Subtract( Begin ).Minutes; } private void SetPrice(decimal Price) { if(Price > High) High = Price; if(Price < Low) Low = Price; } public void SetTime(TimeSpan Time) { if( Time > End ) End = Time; if( Time < Begin ) Begin = Time; } public void SetPriceRange(decimal Price, TimeSpan Time) { SetPrice(Price); SetTime(Time); } } public class Point { public PointType Type = PointType.NA; // Set to Uninitialized public PointDirection Direction; public PointStatus Status; public Range Range = new Range(); public decimal Mean() { return (Range.Low + Range.High)/2; } } public class Position { public string Symbol; public int Quantity; public decimal Price; public Range Opening = new Range(); public decimal Point_A = 0; public decimal Point_C = 0; public Point Point = new Point(); public List<OrderTicket> Tickets = new List<OrderTicket>(); public bool CrossOpenRange() { //return !((Point.Range.Low < Opening.Low || Point.Range.Low > Opening.High) && (Point.Range.High < Opening.Low || Point.Range.High > Opening.High)); return Opening.Low <= Point.Range.High && Point.Range.Low <= Opening.High; } } public class OpeningRange { public string symbol; public decimal high; public decimal low; } public class BasicTemplateAlgorithm : QCAlgorithm { List<Position> Positions = new List<Position>(); Range rangeOpening = new Range(); public void CancelAndClose(Position position) { if(Portfolio.ContainsKey(position.Symbol)) // Sell or Cover Short (--) try { decimal Quantity = Portfolio[position.Symbol].Quantity; if(Quantity!=0) MarketOrder(position.Symbol, -Portfolio[position.Symbol].Quantity); } catch (Exception e) { Debug($"MarketOrder: {e.Message}"); } foreach(OrderTicket ticket in position.Tickets) // Close Open Orders, Cancel all pending orders try { ticket.Cancel(); } catch (Exception e) { Debug($"ticket.Cancel() -> {e.Message}"); } } public void ClearRanges() { foreach (Position position in Positions) { position.Opening = new Range(); position.Point = new Point(); //Debug("Ranges Cleared - Morning"); position.Point_A = 0; position.Point_C = 0; position.Tickets.Clear(); } } public override void Initialize() { // backtest parameters // backtest parameters // backtest parameters // BACKTEST DATES SetStartDate(2019,03,18); SetEndDate(2019, 03, 22); // cash allocation SetCash(300000); Positions.Add(new Position() { Symbol="WYNN" } ); Positions.Add(new Position() { Symbol="SPY" } ); Positions.Add(new Position() { Symbol="QQQ" } ); Positions.Add(new Position() { Symbol="DIA" } ); Positions.Add(new Position() { Symbol="XOP" } ); Positions.Add(new Position() { Symbol="SQ" } ); Positions.Add(new Position() { Symbol="TGT" } ); Positions.Add(new Position() { Symbol="MU" } ); Positions.Add(new Position() { Symbol="FDX" } ); Positions.Add(new Position() { Symbol="CSX" } ); Positions.Add(new Position() { Symbol="FEYE" } ); Positions.Add(new Position() { Symbol="GE" } ); Positions.Add(new Position() { Symbol="PLAY" } ); Positions.Add(new Position() { Symbol="JACK" } ); Positions.Add(new Position() { Symbol="TXN" } ); Positions.Add(new Position() { Symbol="CRON" } ); Positions.Add(new Position() { Symbol="WYNN" } ); Positions.Add(new Position() { Symbol="FIVE" } ); Positions.Add(new Position() { Symbol="SLB" } ); Positions.Add(new Position() { Symbol="GMLP" } ); Positions.Add(new Position() { Symbol="MO" } ); Positions.Add(new Position() { Symbol="T" } ); Positions.Add(new Position() { Symbol="RIO" } ); Positions.Add(new Position() { Symbol="ROKU" } ); Positions.Add(new Position() { Symbol="KEM" } ); Positions.Add(new Position() { Symbol="CARA" } ); Positions.Add(new Position() { Symbol="AMD" } ); Positions.Add(new Position() { Symbol="MSFT" } ); Positions.Add(new Position() { Symbol="AAPL" } ); Positions.Add(new Position() { Symbol="NVDA" } ); Positions.Add(new Position() { Symbol="CGC" } ); Positions.Add(new Position() { Symbol="GLD" } ); //Positions.Add(new Position() { Symbol="GOOG" } ); foreach (Position position in Positions) { AddEquity(position.Symbol, Resolution.Second); } Schedule.On(DateRules.EveryDay(Positions[0].Symbol), TimeRules.At(09,28), () => ClearRanges() ); Schedule.On(DateRules.EveryDay(Positions[0].Symbol), TimeRules.At(9,50), ()=> { string msgBody = $"\nQuant Connect Algorithm 'Logical Trader' by John F. Kallie\n\n" + $"Algorithm Server Local Time: {DateTime.Now.ToString("hh:mm:ss tt")}\n\n"; string msgLine = ""; List<OpeningRange> OpeningRanges = new List<OpeningRange>(); //string payload = "["; foreach (Position position in Positions) { msgLine= $"{position.Symbol.PadRight(4)}\t Opening Range - Low: {position.Opening.Low.ToString("C").PadRight(9)} High: {position.Opening.High.ToString("C").PadRight(9)}" + $" Spread: {(position.Opening.High-position.Opening.Low).ToString("C").PadRight(8)} {((position.Opening.High/position.Opening.Low)-1).ToString("P")}\n"; //payload+="{\"symbol\": \"" + position.Symbol + "\", " + // "\"low\": \"" + DateTime.Now.ToString("yyyy-mm-dd hh:mm:ss") + "\", " + // "\"low\": \"" + position.Opening.Low + "\", " + // "\"high\": \"" + position.Opening.High + "\"}, "; OpeningRanges.Add( new OpeningRange() {symbol=position.Symbol, high=position.Opening.High, low=position.Opening.Low} ); Debug(msgLine+$" Range Time: {position.Opening.Begin.ToString()} - {position.Opening.End}"); msgBody += msgLine; position.Opening.Completed = true; } //payload+="]"; Notify.Email("QuantAlert@ApexMicro.com", "QC Alert: Todays Opening Ranges", $"\nQuant Connect Algorithm 'Logical Trader' by John F. Kallie\n\n" + $"Algorithm Server Local Time: {DateTime.Now.ToString("yyyy-mm-dd hh:mm:ss tt")}\n\n" + msgBody+"\n\n"+JsonConvert.SerializeObject(OpeningRanges)); Notify.Web("https://tradealerts.azurewebsites.net/api/PostOpeningRanges?code=dYQMFetc3PW91/8Aab26xetxFCBmwUS0HpFrJaFOzMomFVxwK30yLA==&clientId=default", JsonConvert.SerializeObject(OpeningRanges)); } ); Schedule.On(DateRules.EveryDay(Positions[0].Symbol), TimeRules.BeforeMarketClose(Positions[0].Symbol,1), ()=> { foreach (Position position in Positions) { CancelAndClose(position); } Debug($"{DateTime.Now.ToString("hh:mm:ss tt")} Cancel and Close all positions."); } ); } // Override the base class event handler for order events public override void OnOrderEvent(OrderEvent orderEvent) { var order = Transactions.GetOrderById(orderEvent.OrderId); Console.WriteLine("{0}: {1}: {2}", Time, order.Type, orderEvent); } /* * New data arrives here. * The "Slice" data represents a slice of time, it has all the data you need for a moment. */ public override void OnData(Slice data) { // slice has lots of useful information TradeBars bars = data.Bars; Splits splits = data.Splits; Dividends dividends = data.Dividends; TimeSpan TickTime = TimeSpan.FromSeconds(0); decimal Price = -1; string Symbol; foreach (Position position in Positions) { Symbol = position.Symbol; if ( data.ContainsKey(Symbol) ) //&& !data[Symbol].Suspicious ) { try { TickTime = data[Symbol].Time.TimeOfDay; } catch (Exception e) { Debug($"TimeSpan:{e.Message}"); } try { Price = data[Symbol].Price; } catch (Exception e) { Debug($"Get Price: {Symbol} Price: {Price} - {e.Message}"); } finally { if (Price>0) { if (!position.Opening.Completed) position.Opening.SetPriceRange(Price, TickTime); else // Not Opening Range { if (position.Point.Type != 0 && position.Point.Type != PointType.NA && position.Point.Status != PointStatus.Failed) // Point Set & NOT Failed { switch (position.Point.Type) { case PointType.A: switch (position.Point.Status) { case PointStatus.Pending: position.Point.Range.SetPriceRange(Price, TickTime); if(position.CrossOpenRange()) { position.Point.Status = PointStatus.Failed; //Debug($"{position.Symbol} Failed A @ {Price}"); } else // Pending & NOT Crossed Open { if(position.Point.Range.Duration() >= 10) { position.Point.Status = PointStatus.Success; Debug($"{position.Symbol}, Point: A, Dir: {position.Point.Direction}, Duration: {position.Point.Range.Duration()} Status:{position.Point.Status} Low:{position.Point.Range.Low} High:{position.Point.Range.High} Mean:{position.Point.Mean()}"); // Setup Point C position.Point_A = position.Point.Mean(); position.Point.Type = PointType.C; position.Point.Status = PointStatus.Pending; if (position.Point.Direction == PointDirection.Up) { position.Point.Direction = PointDirection.Down; position.Point_C = position.Opening.Low - (position.Point_A - position.Opening.High); Debug($"Buy: LimitOrder + {position.Symbol} {position.Point.Mean()} Stop @ {position.Point_C}"); position.Tickets.Add( StopLimitOrder(position.Symbol, 100, position.Point_C, position.Point.Mean())); // A UP Notify.Email("QuantAlert@ApexMicro.com", $"QC Alert: {Symbol} - A-Up @ {position.Point.Mean()} Stop @ {position.Point_C}", $"\nQuant Connect Algorithm 'Logical Trader' by John F. Kallie\n\n" + $"Algorithm Server Local Time: {DateTime.Now.ToString("hh:mm:ss tt")}\n\n" + $"Buy {Symbol} @ {position.Point.Mean()}\n\n" + $"Opening Range: {position.Opening.Low} : {position.Opening.High}\n\n"+ $"A Range: {position.Point.Range.Low} : {position.Point.Range.High}\n\n"); } else // Down { position.Point.Direction = PointDirection.Up; position.Point_C = position.Opening.High + (position.Opening.Low - position.Point_A ); Debug($"Short: LimitOrder - {position.Symbol} {position.Point.Mean()} Stop @ {position.Point_C}"); position.Tickets.Add( StopLimitOrder(position.Symbol, -100, position.Point_C, position.Point.Mean())); // A DOWN Notify.Email("QuantAlert@ApexMicro.com", $"QC Alert: {Symbol} - A-Down @ {position.Point.Mean()} Stop @ {position.Point_C}", $"\nQuant Connect Algorithm 'Logical Trader' by John F. Kallie\n\n" + $"Algorithm Server Local Time: {DateTime.Now.ToString("hh:mm:ss tt")}\n\n" + $"Short {Symbol} @ {position.Point.Mean()}\n\n" + $"Opening Range: {position.Opening.Low} : {position.Opening.High}\n\n"+ $"A Range: {position.Point.Range.Low} : {position.Point.Range.High}\n\n"); } } else // Pending, Not Crossed, Not 10 minutes position.Point.Range.SetPriceRange(Price, TickTime); } break; case PointStatus.Success: break; case PointStatus.Failed: break; default: Debug($"default: {position.Symbol}, Point: A, Direction: {position.Point.Direction}, Status:{position.Point.Status} "); break; } break; case PointType.C: switch (position.Point.Status) { case PointStatus.Pending: // Did CrossRange ? Which Range switch (position.Point.Direction) { case PointDirection.Up: if(Price > position.Point_C) { Debug($"{Symbol} Point C Up {position.Point_C} - Hit @ {Price} TickTime: {TickTime} || Price Check: {data[Symbol].Price} Time Check: {data[Symbol].Time.TimeOfDay}"); //CancelAndClose(position); Notify.Email("QuantAlert@ApexMicro.com", $"QC Alert: {Symbol} - C-Up Triggered @ {Price}", $"\nQuant Connect Algorithm 'Logical Trader' by John F. Kallie\n\n" + $"TickTime: {TickTime}\n\n" + $"Algorithm Server Local Time: {DateTime.Now.ToString("hh:mm:ss tt")}\n\n" + $"Stop Loss Trigger or COVER and CANCEL any SHORTS of {Symbol}\n\n" + $"Opening Range: {position.Opening.Low} : {position.Opening.High}\n\n"+ $"A Range: {position.Point.Range.Low} : {position.Point.Range.High}\n\n"); position.Point.Status = PointStatus.Success; // Just to stop execution } break; case PointDirection.Down: if(Price < position.Point_C) { Debug($"{position.Symbol} Point C-Down {position.Point_C} - Hit @ {Price}"); // TickTime: {TickTime}"); //CancelAndClose(position); Notify.Email("QuantAlert@ApexMicro.com", $"QC Alert: {Symbol} - C-Down Triggered @ {Price}", $"\nQuant Connect Algorithm 'Logical Trader' by John F. Kallie\n\n" + $"TickTime: {TickTime}\n\n" + $"Algorithm Server Local Time: {DateTime.Now.ToString("hh:mm:ss tt")}\n\n" + $"Stop Loss Trigger OR SELL and CANCEL any LONGS of {Symbol}\n\n" + $"Opening Range: {position.Opening.Low} : {position.Opening.High}\n\n"+ $"A Range: {position.Point.Range.Low} : {position.Point.Range.High}\n\n"); position.Point.Status = PointStatus.Success; // Just to stop execution } break; default: Debug("Unknown C Direction"); break; } break; case PointStatus.Success: //Debug($"{position.Symbol} - C Success"); position.Point.Status = PointStatus.Complete; if (TickTime < new TimeSpan(15,00,00)) { // TODO: Need to make Constant at Top of Page! position.Point.Type = PointType.NA; position.Point.Status = PointStatus.Failed; Debug($"{position.Symbol} - C Success -> Restarting Opening Completed"); } break; case PointStatus.Failed: break; case PointStatus.Complete: break; } break; case PointType.D: Debug($"{position.Symbol}, Point: D, Status: {position.Point.Status}"); break; default: Debug($"Point Type Is Unknown: {position.Point.Type}"); break; } } else // No Point Set - Opening Completed { //decimal LastPrice = data[position.Symbol][0].LastPrice; if (Price > position.Opening.High) // Out of Range { position.Point = new Point() { Type = PointType.A, Direction = PointDirection.Up, Status = PointStatus.Pending, Range = new Range() { Low=Price, High=Price, Begin = TickTime, End = TickTime, Completed = false }, }; } else if (Price < position.Opening.Low) // Out of Range Down { position.Point = new Point() { Type = PointType.A, Direction = PointDirection.Down, Status = PointStatus.Pending, Range = new Range() { Low=Price, High=Price, Begin = TickTime, End = TickTime, Completed = false }, }; } } } } } } // Contained Data of Symbol in data } // Next Each Position } } }