Overall Statistics |
Total Trades 630 Average Win 1.72% Average Loss -2.50% Compounding Annual Return -100% Drawdown 56.600% Expectancy -0.480 Net Profit -39.920% Sharpe Ratio -0.335 Probabilistic Sharpe Ratio 0% Loss Rate 69% Win Rate 31% Profit-Loss Ratio 0.69 Alpha 0 Beta 0 Annual Standard Deviation 2.983 Annual Variance 8.901 Information Ratio -0.335 Tracking Error 2.983 Treynor Ratio 0 Total Fees $1962.85 |
using System; using QuantConnect.Data; using QuantConnect.Data.Market; using QuantConnect.Securities; using System.Collections.Generic; using QuantConnect.Data.Consolidators; using QuantConnect.Orders; using System.Linq; //TODO: //figure out how to tell when an order was fulfilled //Notes: //https://www.quantconnect.com/docs/algorithm-reference/trading-and-orders //https://github.com/QuantConnect/Lean/blob/master/Algorithm.CSharp/OrderTicketDemoAlgorithm.cs //https://github.com/QuantConnect/Lean/blob/master/Algorithm.CSharp/MarketOnOpenOnCloseAlgorithm.cs namespace QuantConnect.Algorithm.CSharp { public class BasicTemplateFuturesConsolidationAlgorithm : QCAlgorithm { TradeBar openingTradeBar; QuoteBar openingBar; decimal entryPrice; decimal d = 0.01m; string positionType = ""; Boolean inTrade = false; private const string RootSP500 = Futures.Indices.SP500EMini; public Symbol SP500 = QuantConnect.Symbol.Create(RootSP500, SecurityType.Future, Market.CME); private HashSet<Symbol> _futureContracts = new HashSet<Symbol>(); public override void Initialize() { SetStartDate(2013, 10, 8); SetEndDate(2013, 10, 11); SetCash(1000000); AddSecurity(RootSP500); var futureSP500 = AddFuture(RootSP500, Resolution.Minute); // set our expiry filter for this future chain // SetFilter method accepts TimeSpan objects or integer for days. // The following statements yield the same filtering criteria futureSP500.SetFilter(0, 180); // futureSP500.SetFilter(TimeSpan.Zero, TimeSpan.FromDays(182)); //Schedule.On(DateRules.EveryDay(RootSP500), TimeRules.At(13, 30), ClosePositions); //Schedule.On(DateRules.EveryDay(RootSP500), TimeRules.At(16, 00), ClosePositions); SetBenchmark(x => 0); } void ClosePositions() { openingBar = null; Liquidate(RootSP500); inTrade = false; } public override void OnData(Slice slice) { //var stopPrice = close * 1.001m; //var limitPrice = close - 0.03m; //stopPrice = close * .999m; //limitPrice = close + 0.03m; foreach (var chain in slice.FutureChains) { var contract = ( from futuresContract in chain.Value.OrderBy(x => x.Expiry) where futuresContract.Expiry > Time.Date.AddDays(90) select futuresContract ).FirstOrDefault(); { //Securities.Add(contract.Symbol); foreach (var cntrct in chain.Value) { if (!_futureContracts.Contains(cntrct.Symbol)) { _futureContracts.Add(cntrct.Symbol); if (!Securities.ContainsKey(cntrct.Symbol.ID.ToString())) //if (!Securities.ContainsKey(cntrct.Symbol)) { AddSecurity(cntrct.Symbol); //if (!Securities.ContainsKey(quoteBar.Symbol.ID.ToString())) //{ // AddSecurity(quoteBar.Symbol); //} } var consolidator = new QuoteBarConsolidator(TimeSpan.FromMinutes(1)); consolidator.DataConsolidated += OnDataConsolidated; SubscriptionManager.AddConsolidator(cntrct.Symbol, consolidator); Log("Added new consolidator for " + cntrct.Symbol.Value); } } } } } public void OnDataConsolidated(object sender, QuoteBar quoteBar) //public void OnDataConsolidated(TradeBar bar) { //if (!Securities.Values.Contains()) //if (!Securities.ContainsKey(quoteBar.Symbol.ID.ToString())) //{ // AddSecurity() //} if (Portfolio.Invested) { if (positionType == "long" && quoteBar.Price >= (entryPrice + 0.50m)) { var newTicket = MarketOrder(quoteBar.Symbol, 1, asynchronous: false); if (newTicket.Status != OrderStatus.Filled) { Log("Synchronous market order was not filled synchronously!"); } inTrade = false; } else if (positionType == "short" && quoteBar.Price >= (entryPrice - 0.50m)) { var newTicket = MarketOrder(quoteBar.Symbol, -1, asynchronous: false); if (newTicket.Status != OrderStatus.Filled) { Log("Synchronous market order was not filled synchronously!"); } inTrade = false; } } else if (!Portfolio.Invested && openingBar != null && !inTrade && Securities.ContainsKey(quoteBar.Symbol.ID.ToString())) { if (quoteBar.Close > openingBar.High) { StopLimitOrders(quoteBar.Symbol, OrderType.LongOrder, 1, quoteBar.Close, quoteBar.Close + d); inTrade = true; //StopLimitOrder(RootSP500, 1, quoteBar.Close, quoteBar.Close+d, "LONG ORDER!!"); positionType = "long"; } if (quoteBar.Close < openingBar.Low) { StopLimitOrders(quoteBar.Symbol, OrderType.LongOrder, 1, quoteBar.Close, quoteBar.Close + d); inTrade = true; //StopLimitOrder(RootSP500, -1, quoteBar.Close, quoteBar.Close - d, "SHORT ORDER!!"); positionType = "short"; } } if (quoteBar.Time.Hour == 9 && quoteBar.Time.Minute <= 30) { openingBar = quoteBar; } Log("Portfolio.TotalHoldingsValue: [" + Portfolio.TotalHoldingsValue + "]"); Log("OnDataConsolidated called"); Log(quoteBar.ToString()); } public enum OrderType { LongOrder, ShortOrder } public void StopLimitOrders(string symbol, OrderType orderType, int quantity, decimal stopPrice, decimal limitPrice) { //var stopPrice = close * 1.001m; //var limitPrice = close - 0.03m; //stopPrice = close * .999m; //limitPrice = close + 0.03m; Log("Submitting StopLimitOrder"); OrderTicket newTicket; switch (orderType) { case OrderType.LongOrder: newTicket = StopLimitOrder(symbol, quantity, stopPrice, limitPrice); //_openStopLimitOrders.Add(newTicket); break; case OrderType.ShortOrder: newTicket = StopLimitOrder(symbol, -quantity, stopPrice, limitPrice); //_openStopLimitOrders.Add(newTicket); break; } } private bool TimeIs(int day, int hour, int minute) { return Time.Day == day && Time.Hour == hour && Time.Minute == minute; } public override void OnOrderEvent(OrderEvent orderEvent) { var order = Transactions.GetOrderById(orderEvent.OrderId); Console.WriteLine("{0}: {1}: {2}", Time, order.Type, orderEvent); if (orderEvent.Quantity == 0) { throw new Exception("OrderEvent quantity is Not expected to be 0, it should hold the current order Quantity"); } if (orderEvent.Quantity != order.Quantity) { throw new Exception("OrderEvent quantity should hold the current order Quantity"); } if (order is LimitOrder && orderEvent.LimitPrice == 0 || order is StopLimitOrder && orderEvent.LimitPrice == 0) { throw new Exception("OrderEvent LimitPrice is Not expected to be 0 for LimitOrder and StopLimitOrder"); } if (order is StopMarketOrder && orderEvent.StopPrice == 0) { throw new Exception("OrderEvent StopPrice is Not expected to be 0 for StopMarketOrder"); } } private bool CheckPairOrdersForFills(OrderTicket longOrder, OrderTicket shortOrder) { if (longOrder.Status == OrderStatus.Filled) { Log(shortOrder.OrderType + ": Cancelling short order, long order is filled."); shortOrder.Cancel("Long filled."); return true; } if (shortOrder.Status == OrderStatus.Filled) { Log(longOrder.OrderType + ": Cancelling long order, short order is filled."); longOrder.Cancel("Short filled"); return true; } return false; } } }