Overall Statistics |
Total Trades 10 Average Win 0.20% Average Loss -0.10% Compounding Annual Return 0.795% Drawdown 0.400% Expectancy 1.417 Net Profit 0.714% Sharpe Ratio 0.908 Loss Rate 20% Win Rate 80% Profit-Loss Ratio 2.02 Alpha 0 Beta 0 Annual Standard Deviation 0.009 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $11.96 |
using System; using System.Collections.Generic; using System.Linq; using QuantConnect.Data.Market; using QuantConnect.Data.UniverseSelection; namespace QuantConnect { /* * QuantConnect University: Full Basic Template: * * The underlying QCAlgorithm class is full of helper methods which enable you to use QuantConnect. * We have explained some of these here, but the full algorithm can be found at: * https://github.com/QuantConnect/QCAlgorithm/blob/master/QuantConnect.Algorithm/QCAlgorithm.cs */ public class BasicTemplateAlgorithm : QCAlgorithm { private readonly Dictionary<string, SymbolData> Data = new Dictionary<string, SymbolData>(); //Initialize the data and resolution you require for your strategy: SecurityChanges _changes = SecurityChanges.None; private Boolean doLongEntry; private Boolean CrossExit = true; private Boolean EarlyExit = false; private decimal exitProfit =200; private decimal MRMentry = 80; private Boolean junktrace = false; private string strtrace = ""; public override void Initialize() { //Start and End Date range for the backtest: UniverseSettings.Resolution = Resolution.Hour; SetStartDate(2014, 1, 1); SetEndDate(DateTime.Now.Date.AddDays(-1)); //Cash allocation SetCash(100000); AddUniverse(CoarseSelectionFunction); doLongEntry = true; //doShortEntry = true; } // sort the data by daily dollar volume and take the top 5 symbols public static IEnumerable<Symbol> CoarseSelectionFunction(IEnumerable<CoarseFundamental> coarse) { // sort descending by daily dollar volume var sortedByDollarVolume = coarse.OrderByDescending(x => x.DollarVolume); // take the top 5 entries from our sorted collection var top5 = sortedByDollarVolume.Take(450); // we need to return only the symbols return top5.Select(x => x.Symbol); } //Data Event Handler: New data arrives here. "TradeBars" type is a dictionary of strings so you can access it by symbol. //private DateTime previous; private int mycount; public void OnData(TradeBars data) { //Log ( " :> " + data.Count + "<" + Data.Count + ">" + Time.ToString("u") ); foreach (var symbolData in Data.Values) { //Log (symbolData.Symbol + " :> " +Time.ToString("u") ); if (!Securities.ContainsKey(symbolData.Symbol)) continue; if (!data.ContainsKey(symbolData.Symbol)) continue; if (!symbolData.IsReady) continue; proc_doLongProfit(symbolData); if (symbolData.Done) continue; symbolData.Done = true; proc_doLongEntry(symbolData); proc_doLongExit(symbolData); proc_doShortExit(symbolData); symbolData.lastSma = symbolData.SMA; symbolData.lastSlow = symbolData.slowSMA; } if (mycount != Data.Count) { Log ("Data universe count " + Data.Count); mycount = Data.Count; } } public override void OnSecuritiesChanged(SecurityChanges changes) { _changes = changes; Boolean addSecurity = true; SymbolData sd; foreach (var removed in changes.RemovedSecurities) { try { sd = Data[removed.Symbol];} catch {continue;} if (removed.Invested) { sd.needsRemoving = true; Log ("Open pos. Not wanting to be Removed " + removed.Symbol); //continue; Liquidate(removed.Symbol); } bool z=false ; if ( strtrace == removed.Symbol) z = true; if ( strtrace == "") z = true; if (junktrace && z) Log ("Removing " + removed.Symbol); Data.Remove(removed.Symbol); } foreach (var security in _changes.AddedSecurities) { foreach (var symbolData in Data.Values) { if (security.Symbol == symbolData.Symbol) addSecurity = false; } if (Data.Count >300 ) addSecurity = false; // if (Data.security.Contains(security.Symbol)) continue; if (addSecurity) { Data.Add(security.Symbol, new SymbolData(security.Symbol, this)); var history = History(security.Symbol,1400 ); foreach (var tradeBar in history) { sd = Data[security.Symbol]; sd.MRM.Update(tradeBar.EndTime, tradeBar.Close); sd.SMA.Update(tradeBar.EndTime, tradeBar.Close); sd.slowSMA.Update(tradeBar.EndTime, tradeBar.Close); } } bool z=false ; if ( strtrace == security.Symbol) z = true; if ( strtrace == "") z = true; if (junktrace && z) Log ("addcount = " + Data.Count + " ; " + security.Symbol); //Data.Add(symbol, new SymbolData(symbol, this)); //Log("addChange " + security.Symbol); } junktrace = true; } void proc_doLongEntry(SymbolData d) { if (!doLongEntry)return; if(Portfolio[d.Symbol].Invested) return; bool crossLong = false; if (d.lastSma < d.lastSlow && d.SMA > d.slowSMA) { crossLong = true; } //Log (d.Symbol + " : " +Time.ToString("u") + " Cross " + crossLong + " , " + d.MRM ); if (d.MRM > MRMentry) //if ( MRMentry !=0) { if ( crossLong) { //Order(d.Symbol,100000); try{ SetHoldings(d.Symbol, 0.1m); bool z=false ; if ( strtrace == d.Symbol) z = true; if ( strtrace == "") z = true; if (z) Log (d.Symbol + " : " +"Long Entry"); } catch {Log ("oops");} } } } void proc_doLongExit(SymbolData d) { if(!Portfolio[d.Symbol].Invested) return; if(!Portfolio[d.Symbol].IsLong) return; bool crossShort = false; if (d.lastSma > d.lastSlow && d.SMA < d.slowSMA) crossShort = true; if (Portfolio[d.Symbol].UnrealizedProfit > exitProfit) { Order(d.Symbol,-100000); Log (d.Symbol + " : " +"LLong profit"); } else { if (d.SMA > d.Security.Close && EarlyExit) { //Order(d.Symbol,-100000); SetHoldings(d.Symbol, 0m); bool z=false ; if ( strtrace == d.Symbol) z = true; if ( strtrace == "") z = true; if (z) Log (d.Symbol + " : " +"Long sma exit"); } if (d.SMA > d.Security.Close && CrossExit && crossShort) { //Order(d.Symbol,-100000); SetHoldings(d.Symbol, 0m); bool z=false ; if ( strtrace == d.Symbol) z = true; if ( strtrace == "") z = true; if (z) Log (d.Symbol + " : " +"Long cross sma exit"); } } } void proc_doLongProfit(SymbolData d) { if(!Portfolio[d.Symbol].Invested) return; if(!Portfolio[d.Symbol].IsLong) return; if (Portfolio[d.Symbol].UnrealizedProfit > exitProfit) { //Order(d.Symbol,-100000); SetHoldings(d.Symbol, 0m); bool z=false ; if ( strtrace == d.Symbol) z = true; if ( strtrace == "") z = true; if (z) Log (d.Symbol + " : " +"Long profit"); } } void proc_doShortExit(SymbolData d) { if(!Portfolio[d.Symbol].Invested) return; if(!Portfolio[d.Symbol].IsShort) return; bool crossLong = false; if (d.lastSma < d.lastSlow && d.SMA > d.slowSMA) crossLong = true; if (Portfolio[d.Symbol].UnrealizedProfit > exitProfit) { Order(d.Symbol,100000); Log (d.Symbol + " : " +"Short profit"); } else { if (d.SMA < d.Security.Close && EarlyExit) { Order(d.Symbol,100000); Log (d.Symbol + " : " +"Short sma exit"); } if (d.SMA < d.Security.Close && CrossExit && crossLong) { Order(d.Symbol,100000); Log (d.Symbol + " : " +"Short cross sma exit"); } } } } public class SymbolData { public readonly string Symbol; public readonly Security Security; public readonly SimpleMovingAverage SMA; public readonly SimpleMovingAverage slowSMA; public readonly RateOfChange ROC; public readonly MomersionIndicator MRM; public Boolean Done; public decimal lastSlow; public decimal lastSma; public int Position; public DateTime lastBarTime; public Boolean needsRemoving = false; //public readonly Identity Close; public SymbolData(string symbol, QCAlgorithm algorithm) { Symbol = symbol; Security = algorithm.Securities[symbol]; var consolidator = new TradeBarConsolidator(TimeSpan.FromHours(4)); consolidator.DataConsolidated += mynewbar; SMA = new SimpleMovingAverage(14); slowSMA = new SimpleMovingAverage(21); ROC = new RateOfChange(14); MRM = new MomersionIndicator(5,21); algorithm.RegisterIndicator(symbol, SMA, consolidator, Field.Close); algorithm.RegisterIndicator(symbol, slowSMA, consolidator, Field.Close); algorithm.RegisterIndicator(symbol, ROC, consolidator, Field.Close); algorithm.RegisterIndicator(symbol, MRM, consolidator, Field.Close); } public void mynewbar(Object o, TradeBar bar) { Done = false; } public bool IsReady { get { return SMA.IsReady && slowSMA.IsReady && MRM.IsReady ; } } } }
namespace QuantConnect { // // Make sure to change "BasicTemplateAlgorithm" to your algorithm class name, and that all // files use "public partial class" if you want to split up your algorithm namespace into multiple files. // //public partial class BasicTemplateAlgorithm : QCAlgorithm, IAlgorithm //{ // Extension functions can go here...(ones that need access to QCAlgorithm functions e.g. Debug, Log etc.) //} //public class Indicator //{ // ...or you can define whole new classes independent of the QuantConnect Context //} }