| 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;
}
}
}