Overall Statistics |
Total Trades 24 Average Win 0.33% Average Loss -0.62% Compounding Annual Return -1.108% Drawdown 2.600% Expectancy -0.234 Net Profit -1.751% Sharpe Ratio -0.638 Loss Rate 50% Win Rate 50% Profit-Loss Ratio 0.53 Alpha -0.013 Beta 0.02 Annual Standard Deviation 0.017 Annual Variance 0 Information Ratio -0.945 Tracking Error 0.107 Treynor Ratio -0.534 Total Fees $131.56 |
using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; using QuantConnect.Data; using QuantConnect.Data.Market; using QuantConnect.Data.Consolidators; using System.Collections; using QuantConnect.Securities; using QuantConnect.Models; namespace QuantConnect.Algorithm.Examples { /// <summary> /// Algorithm that detects over night gaps /// </summary> public class GapAlgorithm : QCAlgorithm { //parameters go here const decimal StopLossPercent = 0.012m; const decimal TakeProfitPercent = 1.0m; private OrderTicket CurrentOrder; private OrderTicket StopLoss; private OrderTicket ProfitTarget; // these are open/close minute bars // we'll set the open at the beginning of each day to detect gaps TradeBar open; // we'll set the close at the end of each day TradeBar close; private RateOfChangePercent ROCP_1_CFO ; decimal price = 0; decimal price_1 = 0; decimal price_01 = 1; private string symbol="SPY"; private string symbol_1="SPY"; private decimal gapChange=0.0m; private decimal ROCP_CFO=0.0m; RollingWindow<TradeBar> _window = new RollingWindow<TradeBar>(2); //Set the consolidator period: private TimeSpan _barPeriod = TimeSpan.FromDays(1); //Consolidator Class: private Consolidator _consolidator; //Initialize the data and resolution you require for your strategy: /// <summary> /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized. /// </summary> public override void Initialize() { SetStartDate(2004, 01, 01); //SetStartDate(2009, 01, 01);// // SetStartDate(1998, 01, 01); //SetStartDate(2002, 07, 03); //SetStartDate(2016, 01, 03); //SetEndDate(2016, 02, 01); SetEndDate(2005, 08, 01); //SetEndDate(DateTime.Now.Date.AddDays(-1)); // SetEndDate(2016, 11, 05); AddSecurity(SecurityType.Equity, symbol, Resolution.Minute); AddSecurity(SecurityType.Equity, symbol_1, Resolution.Minute); ROCP_1_CFO = new RateOfChangePercent("SPY", 5); // 252 trading days in a US year // RegisterIndicator(symbol, Resolution.Minute, Field.Close); RegisterIndicator(symbol, ROCP_1_CFO, Resolution.Minute, Field.Close); //Setup Consolidator bar bar _consolidator = new Consolidator(_barPeriod); } /// <param name="data">TradeBars IDictionary object with your stock data</param> public void OnData(TradeBars data) { //Date gets updated until the consolidator period and then returns true: if (_consolidator.Update(data["SPY"])) { var bar = _consolidator.Bar; _window.Add(bar); if (!_window.IsReady) return; } // populate our opening price variable if (open == null || open.Time.Date != Time.Date) { // when TryGetValue succeeds it will populate the 'open' // variable with our first minute bar of the day (at 9:31, the bar that spans from 9:30->9:31) // if it fails then 'open' will have a value of null data.TryGetValue("SPY", out open); if (open != null && close != null && open.Time.Date != close.Time.Date) { // The close of yesterday is greater than the open today. // Gap_Down = Close[1] > Open[0] //bool gapDown = close.Close > open.Open; //decimal gapChange = open.Open/close.Close - 1m; gapChange = open.Open/close.Close - 1m; } } if (!_window.IsReady) return; price = data[symbol].Close; price_1 = data[symbol_1].Close; //Get fresh cash balance: Set purchase quantity to equivalent 10% of portfolio. decimal cash = Portfolio.Cash; int holdings = Portfolio[symbol_1].Quantity; ROCP_CFO = price / open.Open-1.0m; if (( gapChange > 0.001m && Time.TimeOfDay == new TimeSpan(9, 40, 0) ) && ( ROCP_CFO>0.001m && price > _window[0].High ) && ((holdings < 0 || holdings == 0))) { Console.WriteLine(Time + " - GapUp: " + gapChange.ToString("0.000") ); Console.WriteLine(Time + " - CFO: " + ROCP_CFO); //quantity = Convert.ToInt32((cash * 1.0m)/ price_1); // Calculate quantity based on available cash var quantity = (int) (Portfolio.Cash / price_1); price_01=price_1; CurrentOrder = Order(symbol_1, quantity); //Log(Time.ToShortDateString() + "> Go Long > Holdings: " + holdings.ToString() + " Quantity:" + quantity.ToString() + " Samples: " + ROCP_CFO.Samples); // Set StopLoss order StopLoss = StopMarketOrder(symbol_1, -quantity, price_1 * (1m - StopLossPercent)); // Set Profit Target ProfitTarget = LimitOrder(symbol_1, -quantity, price_1 * (1m + TakeProfitPercent)); Log( "ROCP_1_CFO: " + ROCP_1_CFO ); Log( "holdings: " + holdings ); Log( "PT order id: " + ProfitTarget.OrderId); Log( "StopLoss order id: " + StopLoss.OrderId); } if (Time.TimeOfDay.TotalHours == 16) { // when TryGetValue succeeds it will populate the 'close' // variable with our final minute bar of the day (at $:00) // if it fails then 'close' will have a value of null data.TryGetValue("SPY", out close); } // at 3:58 liquidate if (Portfolio.Invested && Time.TimeOfDay == new TimeSpan(15, 58, 0) && (holdings != 0)) { Console.WriteLine(Time + " EOD order: " + holdings ); Log( "3:58pm holdings: " + holdings ); Liquidate(); } } // If the StopLoss or ProfitTarget is filled, cancel the other // If you don't do this, then the ProfitTarget or StopLoss order will remain outstanding // indefinitely, which will cause very bad behaviors in your algorithm public override void OnOrderEvent(OrderEvent orderEvent) { // Ignore OrderEvents that are not closed if (!orderEvent.Status.IsClosed()) { return; } // Defensive check if (ProfitTarget == null || StopLoss == null) { return; } var filledOrderId = orderEvent.OrderId; // If the ProfitTarget order was filled, close the StopLoss order if (ProfitTarget.OrderId == filledOrderId) { Console.WriteLine(Time +" ProfitTarget is filled " +ProfitTarget.OrderId + " Filled Order is " + filledOrderId ); Log( "ProfitTarget is filled " +ProfitTarget.OrderId ); StopLoss.Cancel(); } // If the StopLoss order was filled, close the ProfitTarget if (StopLoss.OrderId == filledOrderId) { Console.WriteLine(Time + " StopLoss Order is filled " +StopLoss.OrderId + " Filled Order is " + filledOrderId ); Log( "StopLoss Order is filled " +StopLoss.OrderId ); ProfitTarget.Cancel(); } } } }
using System; using System.Collections; using System.Collections.Generic; using QuantConnect.Securities; using QuantConnect.Models; namespace QuantConnect { /* * TimeSpanConsolidator Helper Routine: Assemble generic timespan bar lengths: e.g. 10 minutes: * * 1. Setup the new Consolidator class with the timespan period: * var _consolidator = new Consolidator(TimeSpan.FromMinutes(10)); * * 2. Add in the data with the update routine. It will return true when bar ready * if (_consolidator.Update(data["MSFT"])) { UseBar } */ public class Consolidator { private TradeBar _resultBar; private TradeBar _workingBar; private DateTime _start; private TimeSpan _period; //Result: public TradeBar Bar { get { return _resultBar; } } //Constructor: Set the period we'd like to scan public Consolidator(TimeSpan span) { this._period = span; this._resultBar = new TradeBar(); this._workingBar = new TradeBar(new DateTime(), "", Decimal.Zero, Decimal.MinValue, Decimal.MaxValue, 0, 0); } //Submit this bar, return true if we've started a new one. public bool Update(TradeBar newBar) { //Intialize: if (_start == new DateTime()) { _start = newBar.Time; } //While we're less than end date, keep adding to this bar: if (newBar.Time < (_start + _period)) { //Building bar: AddToBar(newBar); return false; } else { //Completed bar: start new one: _resultBar = _workingBar; //Create a new bar: _workingBar = new TradeBar(newBar.Time, newBar.Symbol, Decimal.Zero, Decimal.MinValue, Decimal.MaxValue, 0, 0); //Start of this bar: _start = newBar.Time; AddToBar(newBar); return true; } } //Add to a tradebar private void AddToBar(TradeBar newBar) { //Add this data to working bar: if (_workingBar.Time == new DateTime()) _workingBar.Time = newBar.Time; if (_workingBar.Symbol == "") _workingBar.Symbol = newBar.Symbol; if (_workingBar.Open == Decimal.Zero) _workingBar.Open = newBar.Open; if (newBar.High > _workingBar.High) _workingBar.High = newBar.High; if (newBar.Low < _workingBar.Low) _workingBar.Low = newBar.Low; _workingBar.Close = newBar.Close; _workingBar.Volume = newBar.Volume; } } }