| Overall Statistics |
|
Total Trades 1504 Average Win 0.09% Average Loss -0.10% Annual Return 43.422% Drawdown 1.000% Expectancy 0.718 Net Profit 198.272% Sharpe Ratio 6.972 Loss Rate 8% Win Rate 92% Profit-Loss Ratio 0.86 Alpha 0.242 Beta -0.011 Annual Standard Deviation 0.034 Annual Variance 0.001 Information Ratio 0.488 Tracking Error 0.167 Treynor Ratio -22.187 |
using System;
using System.Collections;
using System.Collections.Generic;
using QuantConnect.Securities;
using QuantConnect.Models;
namespace QuantConnect {
public class SymbolData
{
private Hawkes i = new Hawkes(1, 1.2, 1.8);
private Hawkes b = new Hawkes(1, 1.2, 1.8);
private Hawkes s = new Hawkes(1, 1.2, 1.8);
//private Hawkes s = new Hawkes(1, 1.2, 1.8);
public double LastTradePrice { get; set; }
public DateTime LastTradeTime { get; set; }
public Hawkes Intensity { get { return i; } }
public Hawkes BuyIntensity { get { return b; } }
public Hawkes SellIntensity { get { return s; } }
public double TickSize { get; set; }
public double PrevPrice { get; set; }
public bool upTick { get; set; }
public bool downTick { get; set; }
public DateTime LastTick { get; set; }
public int Qty { get; set; }
}
}using System;
using System.Collections;
using System.Collections.Generic;
using QuantConnect.Securities;
using QuantConnect.Models;
namespace QuantConnect
{
public partial class BasicTemplateAlgorithm : QCAlgorithm, IAlgorithm
{
private readonly bool enableLogging = true;
private Dictionary<string, SymbolData> symbols = new Dictionary<string, SymbolData>();
//Initialize the data and resolution you require for your strategy:
public override void Initialize()
{
//Initialize the start, end dates for simulation; cash and data required.
SetStartDate(new DateTime(2010,01,01));
SetEndDate(new DateTime(2014, 07,25));
SetCash(25000); //Starting Cash in USD.
symbols.Add("SPY", new SymbolData());
symbols.Add("IWM", new SymbolData());
symbols.Add("DIA", new SymbolData());
foreach(var symbol in symbols.Keys)
{
symbols[symbol].TickSize = 0.01;
AddSecurity(SecurityType.Equity, symbol, Resolution.Second);
Securities[symbol].Model = new CustomTransactionModel();
}
}
//Handle TradeBar Events: a TradeBar occurs on a time-interval (second or minute bars)
public override void OnTradeBar(Dictionary<string, TradeBar> data)
{
foreach(var symbol in symbols.Keys)
{
if (data.ContainsKey(symbol))
{
Process(symbol, symbols[symbol], data[symbol]);
}
}
}
public void Process(string symbol, SymbolData d, TradeBar t)
{
double mid = (double)t.Close;//(t.Price);
if (d.PrevPrice == 0)
{
d.PrevPrice = mid;
d.LastTick = t.Time;
return;
}
if (t.Time.Date != d.LastTick.Date)
{
d.PrevPrice = mid;
d.LastTick = t.Time;
return;
}
double pips = Math.Abs(d.PrevPrice - mid)/d.TickSize;
if (pips > 100) return;
double buyintensity = 0;
double sellintensity = 0;
if (d.PrevPrice > mid)
{
buyintensity = d.BuyIntensity.Process(0, true);
sellintensity = d.SellIntensity.Process(pips, !d.downTick);
}
else if (mid > d.PrevPrice)
{
buyintensity = d.BuyIntensity.Process(pips, !d.upTick);
sellintensity = d.SellIntensity.Process(0, true);
}
else
{
buyintensity = d.BuyIntensity.Process(0, true);
sellintensity = d.SellIntensity.Process(0, true);
}
if (Portfolio[symbol].HoldStock)
{
// Stay in the market until the asset is going the wrong direction, i.e. down or up depending on if we're long or short on the market.
if ((t.Time - d.LastTradeTime).TotalSeconds > 60 && ((Portfolio[symbol].IsLong && mid < d.PrevPrice) || (Portfolio[symbol].IsShort && mid > d.PrevPrice)))
{
LogExit(t.Time, symbol, Portfolio[symbol].UnrealizedProfit, (t.Time - d.LastTradeTime).TotalSeconds);
d.LastTradePrice = 0;
Liquidate(symbol);
}
}
int qty = (int)Math.Round(Portfolio.Cash / 4 / (decimal)mid);
if (buyintensity > 10 && buyintensity > sellintensity && !Portfolio[symbol].HoldStock)
{
LogEntry(t.Time, symbol, "SHORT", qty, Portfolio.Cash, mid);
Order(symbol, -qty);
d.Qty = 1;
d.LastTradePrice = mid;
d.LastTradeTime = t.Time;
}
else if (sellintensity > 10 && sellintensity > buyintensity && !Portfolio[symbol].HoldStock)
{
LogEntry(t.Time, symbol, "LONG", qty, Portfolio.Cash, mid);
Order(symbol, qty);
d.Qty = -1;
d.LastTradePrice = mid;
d.LastTradeTime = t.Time;
}
d.upTick = mid > d.PrevPrice;
d.downTick = d.PrevPrice > mid;
d.PrevPrice = mid;
d.LastTick = t.Time;
}
private void LogEntry(DateTime time, string symbol, string tradeAction, int qty, decimal cash, double price)
{
if(enableLogging)
Debug(string.Format("{0} {1} [{2}]. Qty: {3}, Value: {4}, Cash: {5}", time.ToString("yyyyMMdd HH:mm:ss.fff"), symbol, tradeAction, qty, Math.Round(price * qty, 2), cash));
}
private void LogExit(DateTime time, string symbol, decimal profit, double seconds)
{
if(enableLogging)
Debug(string.Format("{0} {1} [EXIT]. Profit: {2}, Seconds: {3}", time.ToString("yyyyMMdd HH:mm:ss.fff"), symbol, Math.Round(profit, 2), seconds));
}
}
}// QuantConnect Simulator C# File, Created on 3-6-2014 by Satyapravin Bezwada
using System;
using System.Collections;
using System.Collections.Generic;
namespace QuantConnect {
public class Hawkes
{
double mu_ = 0, alpha_ = 0, beta_ = 0, bfactor_ = 0;
public Hawkes(double mu, double alpha, double beta)
{
mu_ = mu;
alpha_ = alpha;
beta_ = beta;
}
public double Process( double count, bool decay)
{
double exp = Math.Exp(-beta_);
if (decay) bfactor_ *= exp;
bfactor_ += exp * count;
return mu_ + alpha_ * bfactor_;
}
}
}/*
* QUANTCONNECT.COM - Equity Transaction Model
* Default Equities Transaction Model
*/
/**********************************************************
* USING NAMESPACES
**********************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace QuantConnect.Securities {
/********************************************************
* QUANTCONNECT PROJECT LIBRARIES
*********************************************************/
using QuantConnect.Models;
/********************************************************
* CLASS DEFINITIONS
*********************************************************/
/// <summary>
/// Default Transaction Model for Equity Security Orders
/// </summary>
public class CustomTransactionModel : ISecurityTransactionModel {
/********************************************************
* CLASS PRIVATE VARIABLES
*********************************************************/
/********************************************************
* CLASS PUBLIC VARIABLES
*********************************************************/
/********************************************************
* CLASS CONSTRUCTOR
*********************************************************/
/// <summary>
/// Initialise the Algorithm Transaction Class
/// </summary>
public CustomTransactionModel() {
}
/********************************************************
* CLASS PROPERTIES
*********************************************************/
/********************************************************
* CLASS METHODS
*********************************************************/
/// <summary>
/// Perform neccessary check to see if the model has been filled, appoximate the best we can.
/// </summary>
/// <param name="vehicle">Asset we're working with</param>
/// <param name="order">Order class to check if filled.</param>
public virtual void Fill(Security vehicle, ref Order order) {
try {
switch (order.Type) {
case OrderType.Limit:
LimitFill(vehicle, ref order);
break;
case OrderType.Stop:
StopFill(vehicle, ref order);
break;
case OrderType.Market:
MarketFill(vehicle, ref order);
break;
}
} catch (Exception) {
}
}
/// <summary>
/// Get the Slippage approximation for this order:
/// </summary>
public virtual decimal GetSlippageApproximation(Security security, Order order) {
return 0.15m;
}
/// <summary>
/// Model the slippage on a market order: fixed percentage of order price
/// </summary>
/// <param name="security">Asset we're working with</param>
/// <param name="order">Order to update</param>
public virtual void MarketFill(Security security, ref Order order) {
try {
//Calculate the model slippage: e.g. 0.01c
decimal slip = GetSlippageApproximation(security, order);
switch (order.Direction)
{
case OrderDirection.Buy:
order.Price = security.Price;
order.Price += slip;
break;
case OrderDirection.Sell:
order.Price = security.Price;
order.Price -= slip;
break;
}
//Market orders fill instantly.
order.Status = OrderStatus.Filled;
//Round off:
order.Price = Math.Round(order.Price, 2);
} catch (Exception) {
}
}
/// <summary>
/// Check if the model has stopped out our position yet:
/// </summary>
/// <param name="security">Asset we're working with</param>
/// <param name="order">Stop Order to Check, return filled if true</param>
public virtual void StopFill(Security security, ref Order order) {
try {
//If its cancelled don't need anymore checks:
if (order.Status == OrderStatus.Canceled) return;
//Calculate the model slippage: e.g. 0.01c
decimal slip = GetSlippageApproximation(security, order);
//Check if the Stop Order was filled: opposite to a limit order
switch (order.Direction)
{
case OrderDirection.Sell:
//-> 1.1 Sell Stop: If Price below setpoint, Sell:
if (security.Price < order.Price) {
order.Status = OrderStatus.Filled;
order.Price = security.Price;
order.Price -= slip;
}
break;
case OrderDirection.Buy:
//-> 1.2 Buy Stop: If Price Above Setpoint, Buy:
if (security.Price > order.Price) {
order.Status = OrderStatus.Filled;
order.Price = security.Price;
order.Price += slip;
}
break;
}
//Round off:
order.Price = Math.Round(order.Price, 2);
} catch (Exception) {
}
}
/// <summary>
/// Check if the price MarketDataed to our limit price yet:
/// </summary>
/// <param name="security">Asset we're working with</param>
/// <param name="order">Limit order in market</param>
public virtual void LimitFill(Security security, ref Order order) {
//Initialise;
decimal marketDataMinPrice = 0;
decimal marketDataMaxPrice = 0;
try {
//If its cancelled don't need anymore checks:
if (order.Status == OrderStatus.Canceled) return;
//Calculate the model slippage: e.g. 0.01c
decimal slip = GetSlippageApproximation(security, order);
//Depending on the resolution, return different data types:
BaseData marketData = security.GetLastData();
marketDataMinPrice = marketData.Value;
marketDataMaxPrice = marketData.Value;
//-> Valid Live/Model Order:
switch (order.Direction)
{
case OrderDirection.Buy:
//Buy limit seeks lowest price
if (marketDataMinPrice < order.Price) {
order.Status = OrderStatus.Filled;
order.Price = security.Price;
order.Price += slip;
}
break;
case OrderDirection.Sell:
//Sell limit seeks highest price possible
if (marketDataMaxPrice > order.Price) {
order.Status = OrderStatus.Filled;
order.Price = security.Price;
order.Price -= slip;
}
break;
}
//Round off:
order.Price = Math.Round(order.Price, 2);
} catch (Exception) {
}
}
/// <summary>
/// Get the fees from one order, interactive brokers model.
/// </summary>
/// <param name="quantity"></param>
/// <param name="price"></param>
public virtual decimal GetOrderFee(decimal quantity, decimal price) {
decimal tradeFee = 0;
quantity = Math.Abs(quantity);
decimal tradeValue = (price * quantity);
//Per share fees
if (quantity < 500) {
tradeFee = quantity * 0.013m;
} else {
tradeFee = quantity * 0.008m;
}
//Maximum Per Order: 0.5%
//Minimum per order. $1.0
if (tradeFee < 1) {
tradeFee = 1;
} else if (tradeFee > (0.005m * tradeValue)) {
tradeFee = 0.005m * tradeValue;
}
//Always return a positive fee.
return Math.Abs(tradeFee);
}
} // End Algorithm Transaction Filling Classes
} // End QC Namespace