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