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