| Overall Statistics |
|
Total Trades 628 Average Win 1.13% Average Loss -0.67% Compounding Annual Return -0.831% Drawdown 23.000% Expectancy -0.051 Net Profit -4.087% Sharpe Ratio 0.024 Probabilistic Sharpe Ratio 0.434% Loss Rate 65% Win Rate 35% Profit-Loss Ratio 1.67 Alpha -0.079 Beta 0.447 Annual Standard Deviation 0.134 Annual Variance 0.018 Information Ratio -1.261 Tracking Error 0.144 Treynor Ratio 0.007 Total Fees $1778.53 Estimated Strategy Capacity $11000000.00 Lowest Capacity Asset ADSK R735QTJ8XC9X |
#region imports
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Drawing;
using QuantConnect;
using QuantConnect.Algorithm.Framework;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Parameters;
using QuantConnect.Benchmarks;
using QuantConnect.Brokerages;
using QuantConnect.Util;
using QuantConnect.Interfaces;
using QuantConnect.Algorithm;
using QuantConnect.Indicators;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Custom;
using QuantConnect.DataSource;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Notifications;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Orders.Fills;
using QuantConnect.Orders.Slippage;
using QuantConnect.Scheduling;
using QuantConnect.Securities;
using QuantConnect.Securities.Equity;
using QuantConnect.Securities.Future;
using QuantConnect.Securities.Option;
using QuantConnect.Securities.Forex;
using QuantConnect.Securities.Crypto;
using QuantConnect.Securities.Interfaces;
using QuantConnect.Storage;
using QuantConnect.Data.Custom.AlphaStreams;
using QCAlgorithmFramework = QuantConnect.Algorithm.QCAlgorithm;
using QCAlgorithmFrameworkBridge = QuantConnect.Algorithm.QCAlgorithm;
#endregion
namespace QuantConnect.Algorithm.CSharp
{
public class LongTrendVolatility : QCAlgorithm
{
/********** Const ************/
const string BENCHMARK = "QQQ";
/// Used to Enable Ticker List For Specialized Runs
const bool ENABLE_TICKER_LIST = false;
const int ROLLING_WINDOW_COUNT = 21;
const int NUM_POSITIONS = 8;
decimal POSITION_SIZE;
/********** Vars ************/
int _LastYear = -1;
// Start Times
/// START BACK 1 MONTH FOR WARMUP
DateTime startDate = new DateTime(2009, 1, 1);
DateTime endDate = new DateTime(2014, 1, 1);
/********** Structures ************/
string[] _TickerList = {"NFLX", "MED", "AMZN", "NUS", "TPX", "TUP", "SHOO", "CROX",
"F", "FDS", "RJF", "GNW", "MIDD", "LULU", "CAR", "MELI", "DDS", "ODP", "RPM",
"NEU", "DECK", "SKX", "PVH", "HBI", "BC", "DAN", "SWK", "CHKP", "SWKS", "MRVL"};
// Map Symbols to their Rolling Window of Tradebar Data
Dictionary<Symbol, RollingWindow<TradeBar>> _WindowDict = new Dictionary<Symbol, RollingWindow<TradeBar>>();
// Map Symbols to their Indicator Data
Dictionary<Symbol, SymbolData> _SymbolDict = new Dictionary<Symbol, SymbolData>();
// Industry Group Mapping
Dictionary<int, string> _Industries = new Dictionary<int, string>();
// Mapping Stocks To Their Industry Group
Dictionary<int, List<Security>> _IndustryStocks = new Dictionary <int, List<Security>>();
Dictionary<Symbol, TradeStruct> _TradeInfo = new Dictionary<Symbol, TradeStruct>();
/********** Methods ************/
public override void Initialize()
{
POSITION_SIZE = 1m / NUM_POSITIONS;
SetStartDate(startDate);
SetEndDate(endDate);
SetCash(100000);
UniverseSettings.Resolution = Resolution.Daily;
UniverseSettings.DataNormalizationMode = DataNormalizationMode.SplitAdjusted;
EnableAutomaticIndicatorWarmUp = true;
//AddUniverseSelection(new FineFundamentalUniverseSelectionModel(SelectCoarse, SelectFine));
///AddUniverseSelection(new FineFundamentalUniverseSelectionModel(SelectCoarse, SelectRussell500));
///AddUniverseSelection(new FineFundamentalUniverseSelectionModel(SelectCoarse, SelectRussell));
AddUniverseSelection(new FineFundamentalUniverseSelectionModel(SelectCoarse, SelectNdx100));
//AddUniverseSelection(new FineFundamentalUniverseSelectionModel(SelectCoarse, SelectNdx200));
var security = AddEquity(BENCHMARK, Resolution.Daily);
SetBenchmark(BENCHMARK);
/// Setup Industry Mapping
Type type = typeof(MorningstarIndustryCode); // MyClass is static class with static properties
foreach (var p in type.GetFields( System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public
))
{
object v = p.GetValue(null); // static classes cannot be instanced, so use null...=
var industryCode = v.ToString().ToInt32();
_Industries[industryCode] = p.Name;
_IndustryStocks[industryCode] = new List<Security>();
}
Schedule.On(Schedule.DateRules.EveryDay(),
Schedule.TimeRules.AfterMarketOpen(security.Symbol, 1), LowVolTrend);
SetWarmUp(new TimeSpan(252, 0, 0, 0));
}
public override void OnEndOfAlgorithm()
{
Liquidate();
base.OnEndOfAlgorithm();
}
public void LowVolTrend()
{
if(IsWarmingUp)
{
return;
}
Transactions.CancelOpenOrders();
/// Update Stop Loss If Necessary
/// Close Any Trades and Remove Them If Necessary
int lNumberOfPositionsToOpen = NUM_POSITIONS - (_TradeInfo.Count);
UpdateOpenPositions();
if(ActiveSecurities[BENCHMARK].Close < (_SymbolDict[BENCHMARK].FiftySma))
{
Liquidate();
_TradeInfo.Clear();
return;
}
if(ActiveSecurities[BENCHMARK].Close < (_SymbolDict[BENCHMARK].FiftySma + (_SymbolDict[BENCHMARK].Atr*1)))
{
return;
}
if(lNumberOfPositionsToOpen == 0)
{
return;
}
var lStocksToTrade = (from pair in _SymbolDict
where ActiveSecurities.ContainsKey(pair.Key)
where _WindowDict.ContainsKey(pair.Key)
where _WindowDict[pair.Key].Count == ROLLING_WINDOW_COUNT
where pair.Key != BENCHMARK
&& _SymbolDict[pair.Key].AverageDollarVolume > 14000000
&& ActiveSecurities[pair.Key].Close > 1
&& ActiveSecurities[pair.Key].Close < 175
&& !ActiveSecurities[pair.Key].Invested
&& _SymbolDict[pair.Key].FiftyDayHigh.PeriodsSinceMaximum == 0
&& _SymbolDict[pair.Key].RSI > 50
orderby (ActiveSecurities[pair.Key].Close / _SymbolDict[pair.Key].FiftyDayLow) descending
select pair.Key).Take(lNumberOfPositionsToOpen).ToList();
foreach(var lPotentialTrade in lStocksToTrade)
{
var lTarget = POSITION_SIZE * 0.98m;
var lQuantity = CalculateOrderQuantity(lPotentialTrade, lTarget);
bool lCanTrade = true;
if(ActiveSecurities[lPotentialTrade].Close * lQuantity > Portfolio.MarginRemaining)
{
lCanTrade = false;
}
if(lCanTrade)
{
/// SetHoldings(lPotentialTrade, POSITION_SIZE * 0.98m);
var limitPrice = ActiveSecurities[lPotentialTrade].Close;
LimitOrder(lPotentialTrade, lQuantity, limitPrice, "BUY");
/// Add Stock and Initial Stop Loss
/// decimal lStopLoss = ActiveSecurities[lPotentialTrade].Close - ( (_SymbolDict[lPotentialTrade].Atr) * 5.0m);
/// Wider Stops Seemed to have Worked Better Russell Style Stocks
/// decimal lStopLoss = ActiveSecurities[lPotentialTrade].Close - ( (_SymbolDict[lPotentialTrade].Atr) * 3.5m);
decimal lStopLoss = limitPrice - ( (_SymbolDict[lPotentialTrade].Atr) * 2.0m);
decimal lTarg = limitPrice + ( (_SymbolDict[lPotentialTrade].Atr) * 5.0m);
_TradeInfo[lPotentialTrade] = new TradeStruct(lStopLoss, ActiveSecurities[lPotentialTrade].Close, lTarg);
}
}
}
public void UpdateOpenPositions()
{
List<Symbol> lClosedPositions = new List<Symbol>();
foreach(var openPositionPair in _TradeInfo)
{
if(!ActiveSecurities.ContainsKey(openPositionPair.Key) || !ActiveSecurities[openPositionPair.Key].Invested || !_SymbolDict.ContainsKey(openPositionPair.Key))
{
lClosedPositions.Add(openPositionPair.Key);
continue;
}
/*if(ActiveSecurities[openPositionPair.Key].Close < _SymbolDict[openPositionPair.Key].FifteenEma)
{
lClosedPositions.Add(openPositionPair.Key);
continue;
}*/
openPositionPair.Value.CurrentHigh = Math.Max(openPositionPair.Value.CurrentHigh, ActiveSecurities[openPositionPair.Key].High);
/// var trailingMultiplier = ActiveSecurities[BENCHMARK].Close < _SymbolDict[BENCHMARK].FiftySma ? 0.8m : 0.8;
var trailingMultiplier = ActiveSecurities[BENCHMARK].Close < _SymbolDict[BENCHMARK].FiftySma ? 0.82m : 0.775m;
///var trailingMultiplier = ActiveSecurities[BENCHMARK].Close < _SymbolDict[BENCHMARK].FiftySma ? 0.82m : 0.725m;
/*trailingMultiplier = ActiveSecurities[openPositionPair.Key].Close < (_SymbolDict[openPositionPair.Key].FiftySma - (_SymbolDict[openPositionPair.Key].Atr*2.5m))
? 0.86m : trailingMultiplier;*/
var lTrailValue = openPositionPair.Value.CurrentHigh * trailingMultiplier;
///var lAtrTrail = openPositionPair.Value.CurrentHigh - (_SymbolDict[openPositionPair.Key].Atr * 7.5m);
///openPositionPair.Value.StopLoss = Math.Max(openPositionPair.Value.StopLoss, lTrailValue);
if(ActiveSecurities[openPositionPair.Key].Close < openPositionPair.Value.StopLoss ||
ActiveSecurities[openPositionPair.Key].Close > openPositionPair.Value.Target)
{
lClosedPositions.Add(openPositionPair.Key);
}
/// 15 Ema Trailing Adjustment Stop
/*if(ActiveSecurities[openPositionPair.Key].Close < _SymbolDict[openPositionPair.Key].FifteenEma)
{
openPositionPair.Value.StopLoss = Math.Max(openPositionPair.Value.StopLoss, ActiveSecurities[openPositionPair.Key].Low * 0.99m);
}*/
}
foreach(var lClosedTrade in lClosedPositions)
{
_TradeInfo.Remove(lClosedTrade);
Liquidate(lClosedTrade);
}
}
public void WindowBarHandler(object sender, TradeBar windowBar)
{
if(!_WindowDict.ContainsKey(windowBar.Symbol))
{
_WindowDict[windowBar.Symbol] = new RollingWindow<TradeBar>(ROLLING_WINDOW_COUNT);
}
_WindowDict[windowBar.Symbol].Add(windowBar);
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
// if we have no changes, do nothing
if (changes == SecurityChanges.None) return;
foreach (var security in changes.RemovedSecurities)
{
if(_SymbolDict.ContainsKey(security.Symbol))
{
_SymbolDict.Remove(security.Symbol);
}
if(security.Fundamentals != null)
{
var lCode = security.Fundamentals.AssetClassification.MorningstarIndustryCode;
if(_IndustryStocks.ContainsKey(lCode))
{
_IndustryStocks[lCode].Remove(security);
}
}
}
foreach (var security in changes.AddedSecurities)
{
if(!_SymbolDict.ContainsKey(security.Symbol) && security.IsTradable)
{
security.SetLeverage(1);
_SymbolDict.Add(security.Symbol, new SymbolData(security.Symbol, this));
var consolidator = new TradeBarConsolidator(TimeSpan.FromDays(1));
consolidator.DataConsolidated += WindowBarHandler;
SubscriptionManager.AddConsolidator(security.Symbol, consolidator);
if(security.Fundamentals != null)
{
var lCode = security.Fundamentals.AssetClassification.MorningstarIndustryCode;
if(_IndustryStocks.ContainsKey(lCode))
{
_IndustryStocks[lCode].Add(security);
}
}
}
}
}
IEnumerable<Symbol> SelectCoarse(IEnumerable<CoarseFundamental> coarse)
{
if (Time.Year == _LastYear)
{
return Universe.Unchanged;
}
var sortedByDollarVolume =
(from x in coarse
where x.HasFundamentalData && x.DollarVolume > 0 && x.Price > 0
&& DoesTickerExist(x.Symbol.Value)
orderby x.DollarVolume descending
select x.Symbol).ToList();
return sortedByDollarVolume;
}
IEnumerable<Symbol> SelectFine(IEnumerable<FineFundamental> fine)
{
var filteredFine =
(from x in fine
where (x.CompanyReference.PrimaryExchangeID == "NAS" || x.CompanyReference.PrimaryExchangeID == "NYS" )
where x.MarketCap > 100000000
where x.MarketCap < 15000000000
orderby x.MarketCap descending
select x.Symbol).Take(1000).ToList();
_LastYear = Time.Year;
return filteredFine;
}
IEnumerable<Symbol> SelectRussell(IEnumerable<FineFundamental> fine)
{
var filteredFine =
(from x in fine
where (x.CompanyReference.PrimaryExchangeID == "NAS" || x.CompanyReference.PrimaryExchangeID == "NYS" )
orderby x.MarketCap descending
select x.Symbol).Take(1000).ToList();
_LastYear = Time.Year;
return filteredFine;
}
IEnumerable<Symbol> SelectRussell500(IEnumerable<FineFundamental> fine)
{
var filteredFine =
(from x in fine
where (x.CompanyReference.PrimaryExchangeID == "NAS" || x.CompanyReference.PrimaryExchangeID == "NYS" )
orderby x.MarketCap descending
select x.Symbol).Take(500).ToList();
_LastYear = Time.Year;
return filteredFine;
}
IEnumerable<Symbol> SelectRussellModified(IEnumerable<FineFundamental> fine)
{
var filteredFine =
(from x in fine
where (x.CompanyReference.PrimaryExchangeID == "NAS" || x.CompanyReference.PrimaryExchangeID == "NYS" )
orderby x.MarketCap descending
select x).Take(1000);
var russell = (from x in filteredFine
where x.Price < 300
select x.Symbol).ToList();
_LastYear = Time.Year;
return russell;
}
IEnumerable<Symbol> SelectNdx100(IEnumerable<FineFundamental> fine)
{
var filteredFine =
(from x in fine
where (x.CompanyReference.PrimaryExchangeID == "NAS")
where x.AssetClassification.MorningstarSectorCode != MorningstarSectorCode.FinancialServices
orderby x.MarketCap descending
select x.Symbol).Take(100).ToList();
_LastYear = Time.Year;
return filteredFine;
}
IEnumerable<Symbol> SelectNdx200(IEnumerable<FineFundamental> fine)
{
var filteredFine =
(from x in fine
where (x.CompanyReference.PrimaryExchangeID == "NAS")
where x.AssetClassification.MorningstarSectorCode != MorningstarSectorCode.FinancialServices
orderby x.MarketCap descending
select x.Symbol).Take(200).ToList();
_LastYear = Time.Year;
return filteredFine;
}
public bool DoesTickerExist(string ticker)
{
if(!ENABLE_TICKER_LIST)
{
return true;
}
bool tickerExists = false;
foreach(var symbol in _TickerList)
{
if(ticker == symbol)
{
tickerExists = true;
break;
}
}
return tickerExists;
}
}
public class TradeStruct
{
public decimal StopLoss;
public decimal CurrentHigh;
public decimal Target;
public TradeStruct(decimal aStopLoss, decimal aHigh, decimal aTarg)
{
StopLoss = aStopLoss;
CurrentHigh = aHigh;
Target = aTarg;
}
}
public class SymbolData
{
Symbol _Symbol;
QCAlgorithm _Algorithm;
public AverageTrueRange Atr;
public SimpleMovingAverage AveragePrice;
public SimpleMovingAverage FiftySma;
public ExponentialMovingAverage TwoHundredEma;
public ExponentialMovingAverage FifteenEma;
public SimpleMovingAverage AverageDollarVolume;
public RateOfChangePercent FiftyDayChange;
public Maximum FiftyDayHigh;
public Minimum FiftyDayLow;
public RateOfChangePercent oneMonth;
public RateOfChangePercent threeMonth;
public RateOfChangePercent sixMonth;
public RateOfChangePercent nineMonth;
public RateOfChangePercent twelveMonth;
public RelativeStrengthIndex RSI;
public SymbolData(Symbol aSymbol, QCAlgorithm aAlgorithm)
{
_Symbol = aSymbol;
_Algorithm = aAlgorithm;
RSI = aAlgorithm.RSI(aSymbol, 30);
/// Indicator Setup
Atr = aAlgorithm.ATR(aSymbol, 63, MovingAverageType.Simple, Resolution.Daily);
AveragePrice = aAlgorithm.SMA(aSymbol, 63, Resolution.Daily);
FiftySma = aAlgorithm.SMA(aSymbol, 50, Resolution.Daily);
TwoHundredEma = aAlgorithm.EMA(aSymbol, 200);
FifteenEma = aAlgorithm.EMA(aSymbol, 15);
AverageDollarVolume = aAlgorithm.SMA(aSymbol, 63, Resolution.Daily, x => ( ((TradeBar)x).Volume * ((TradeBar)x).Close ));
FiftyDayChange = aAlgorithm.ROCP(aSymbol, 50);
FiftyDayHigh = aAlgorithm.MAX(aSymbol, 50, Resolution.Daily, x => ( ((TradeBar)x).Close ));
FiftyDayLow = aAlgorithm.MIN(aSymbol, 50, Resolution.Daily, x => ( ((TradeBar)x).Low ));
/*oneMonth = aAlgorithm.ROCP(aSymbol, 21, Resolution.Daily);
threeMonth = aAlgorithm.ROCP(aSymbol, 63, Resolution.Daily);
sixMonth = aAlgorithm.ROCP(aSymbol, 126, Resolution.Daily);
nineMonth = aAlgorithm.ROCP(aSymbol, 189, Resolution.Daily);
twelveMonth = aAlgorithm.ROCP(aSymbol, 252, Resolution.Daily);*/
}
public decimal AdrPercent
{
get
{
return (Atr / AveragePrice) * 100;
}
}
public decimal IbdRs
{
get
{
// return (twelveMonth*0.2m) + nineMonth + sixMonth + threeMonth;
return (twelveMonth*2.0m) + nineMonth + sixMonth + threeMonth;
}
}
}
}