Overall Statistics |
Total Trades 20 Average Win 0.17% Average Loss -1.46% Compounding Annual Return -4.557% Drawdown 10.300% Expectancy -0.860 Net Profit -9.622% Sharpe Ratio -1.034 Loss Rate 88% Win Rate 12% Profit-Loss Ratio 0.12 Alpha -0.038 Beta 0.01 Annual Standard Deviation 0.036 Annual Variance 0.001 Information Ratio -1.197 Tracking Error 0.114 Treynor Ratio -3.734 Total Fees $65.56 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using QuantConnect.Data.Market; using QuantConnect.Indicators; using QuantConnect.Orders; namespace QuantConnect.Algorithm.MyStrategy.test1 { public class TotalReturnData { private decimal _sumOfDividends; public readonly Identity Close; public readonly IndicatorBase<IndicatorDataPoint> TotalReturnClose; public readonly Symbol Symbol; public decimal SumOfDividends { get { return _sumOfDividends; } } public TotalReturnData(Symbol symbol, QCAlgorithm algorithm) { Symbol = symbol; Close = algorithm.Identity(symbol); TotalReturnClose = new FunctionalIndicator<IndicatorDataPoint>( "TotalReturn_" + Symbol, // total return is close + sum of dividends input => input + _sumOfDividends, // we're ready if Close is ready ind => Close.IsReady ); } public void OnData(Dividend dividend) { _sumOfDividends += dividend.Distribution; } } public class ETFSymbol { public string Symbol; public TotalReturnData TotalReturn { get; set; } public RateOfChangePercent ShortPerformance { get; set; } public RateOfChangePercent LongPerformance { get; set; } public StandardDeviation vol { get; set; } public int rank1 { get; set; } public int rank2 { get; set; } public int rank3 { get; set; } public int totalRank { get; set; } public bool isReady { get { return ShortPerformance.IsReady && LongPerformance.IsReady && vol.IsReady; } } public decimal ObjectiveScore { get { decimal weight1 = 0.3m; decimal weight2 = 0.3m; decimal weight3 = 0.4m; return (weight1 * rank1 + weight2 * rank2 + weight3 * rank3); } } public int totalRankAdjusted { get; set; } } }
/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using QuantConnect.Data.Market; using QuantConnect.Indicators; using QuantConnect.Orders; namespace QuantConnect.Algorithm.MyStrategy.test1 { // Another note, it looks like collaboration is working. // I clicked the 'Share' button on the left and sent the // invite to 'michael@quantconnect.com' and it just worked. public class ETFRotation20150623 : QCAlgorithm { // we use this to tell us when the month has ended DateTime LastRotationTime = DateTime.MinValue; TimeSpan RotationInterval = TimeSpan.FromDays(1); bool isRiskon = false; bool isProtectionOn = false; public Identity GOOG_Close, AAPL_Close; public IndicatorBase<IndicatorDataPoint> GOOG_Over_AAPL, SMA_GOOG_Over_AAPL; public bool isTradeDay = false; private bool first = true; List<string> SymbolList1 = new List<string> { "AA", "AMZN", "TWTR", "SHY", "TLT" }; List<string> SectorSymbols = new List<string> { }; List<string> SymbolList2 = new List<string> { "SHY", "TLT" }; List<DateTime> LastBday = new List<DateTime> { new DateTime(2015, 1, 30), new DateTime(2015, 2, 27), new DateTime(2015, 3, 31), new DateTime(2015, 4, 30), new DateTime(2015, 5, 29), new DateTime(2015, 6, 30), new DateTime(2015, 7, 31), new DateTime(2015, 8, 31), }; // we hold computed data in these guys List<ETFSymbol> IndustryData = new List<ETFSymbol>(); List<ETFSymbol> SectorData = new List<ETFSymbol>(); List<ETFSymbol> BondData = new List<ETFSymbol>(); List<ETFSymbol> RankedIndustryData = new List<ETFSymbol>(); List<ETFSymbol> RankedSectorData = new List<ETFSymbol>(); List<ETFSymbol> RankedBondData = new List<ETFSymbol>(); Dictionary<Symbol, ETFSymbol> SymbolData = new Dictionary<Symbol, ETFSymbol>(); public List<ETFSymbol> findRanking(List<ETFSymbol> ETFList) { int n = 1; var rankedETFList1 = ETFList.OrderByDescending(o => o.ShortPerformance).ToList(); foreach (ETFSymbol ETF in rankedETFList1) { ETF.rank1 = n; // Console.WriteLine("{0} => {1}", ETF.Symbol, ETF.ShortPerformance); n++; } var rankedETFList2 = rankedETFList1.OrderByDescending(o => o.LongPerformance).ToList(); ; n = 1; foreach (ETFSymbol ETF in rankedETFList2) { ETF.rank2 = n; //Console.WriteLine("{0} => {1}", ETF.Symbol, ETF.LongPerformance); n++; } var rankedETFList3 = rankedETFList2.OrderBy(o => o.vol).ToList(); ; n = 1; foreach (ETFSymbol ETF in rankedETFList3) { ETF.rank3 = n; //Console.WriteLine("{0} => {1}", ETF.Symbol, ETF.vol); n++; } var rankedETFList = rankedETFList3.OrderBy(o => o.ObjectiveScore).ToList(); ; n = 1; foreach (ETFSymbol ETF in rankedETFList) { ETF.totalRank = n; //Console.WriteLine("{0} => {1}", ETF.Symbol, ETF.ObjectiveScore); n++; } return rankedETFList; } /// <summary> /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized. /// </summary> public override void Initialize() { SetCash(100000); SetStartDate(2013, 6, 30); SetEndDate(2015, 8, 31); AddSecurity(SecurityType.Equity, "GOOG", Resolution.Minute); AddSecurity(SecurityType.Equity, "AAPL", Resolution.Minute); Securities["GOOG"].SetDataNormalizationMode(DataNormalizationMode.Raw); Securities["AAPL"].SetDataNormalizationMode(DataNormalizationMode.Raw); GOOG_Close = new Identity("GOOG"); AAPL_Close = new Identity("AAPL"); RegisterIndicator("GOOG", GOOG_Close, Resolution.Daily, Field.Close); RegisterIndicator("AAPL", AAPL_Close, Resolution.Daily, Field.Close); GOOG_Over_AAPL = GOOG_Close.Over(AAPL_Close, "Ratio"); SMA_GOOG_Over_AAPL = new SimpleMovingAverage("SMA_Ratio", 120).Of(GOOG_Over_AAPL); foreach (var symbol in SymbolList1) { // should move this init logic into the ETFSymbol class so it // doesn't need to be duplicated for each symbol type AddSecurity(SecurityType.Equity, symbol, Resolution.Minute); Securities[symbol].SetDataNormalizationMode(DataNormalizationMode.Raw); var shortPerformance = ROCP(symbol, 10, Resolution.Daily); var longPerformance = ROCP(symbol, 20, Resolution.Daily); var dailyReturn = ROCP(symbol, 1, Resolution.Daily); var volitality = new StandardDeviation("6Month Vol ROCP", 50).Of(dailyReturn); IndustryData.Add(new ETFSymbol { Symbol = symbol, ShortPerformance = shortPerformance, LongPerformance = longPerformance, vol = volitality, TotalReturn = new TotalReturnData(symbol, this) }); SymbolData[symbol] = IndustryData.Last(); } foreach (var symbol in SectorSymbols) { // should move this init logic into the ETFSymbol class so it // doesn't need to be duplicated for each symbol type AddSecurity(SecurityType.Equity, symbol, Resolution.Minute); Securities[symbol].SetDataNormalizationMode(DataNormalizationMode.Raw); var shortPerformance = ROCP(symbol, 10, Resolution.Daily); var longPerformance = ROCP(symbol, 20, Resolution.Daily); var dailyReturn = ROCP(symbol, 1, Resolution.Daily); var volitality = new StandardDeviation("6Month Vol ROCP", 50).Of(dailyReturn); SectorData.Add(new ETFSymbol { Symbol = symbol, ShortPerformance = shortPerformance, LongPerformance = longPerformance, vol = volitality, TotalReturn = new TotalReturnData(symbol, this) }); SymbolData[symbol] = SectorData.Last(); } foreach (var symbol in SymbolList2) { // should move this init logic into the ETFSymbol class so it // doesn't need to be duplicated for each symbol type Securities[symbol].SetDataNormalizationMode(DataNormalizationMode.Raw); var shortPerformance = ROCP(symbol, 10, Resolution.Daily); var longPerformance = ROCP(symbol, 20, Resolution.Daily); var dailyReturn = ROCP(symbol, 1, Resolution.Daily); var volitality = new StandardDeviation("3Month Vol ROCP", 40).Of(dailyReturn); BondData.Add(new ETFSymbol { Symbol = symbol, ShortPerformance = shortPerformance, LongPerformance = longPerformance, vol = volitality, TotalReturn = new TotalReturnData(symbol, this) }); SymbolData[symbol] = BondData.Last(); } } // this is where dividend events are fired within the algorithm public void OnData(Dividends data) { foreach (var kvp in data) { var symbol = kvp.Key; var dividend = kvp.Value; ETFSymbol symbolData; if (SymbolData.TryGetValue(symbol, out symbolData)) { Debug("Applied dividend for " + symbol + " with distrubution of " + dividend.Distribution.SmartRounding()); symbolData.TotalReturn.OnData(dividend); } } } /// <summary> /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. /// </summary> /// <param name="data">TradeBars IDictionary object with your stock data</param> public void OnData(TradeBars data) { try { if (first) { first = false; LastRotationTime = data.Time; return; } if (data.Time.Hour == 16 && data.Time.Minute == 00) { if(2015 == data.Time.Year && 8 == data.Time.Month && 31 == data.Time.Day) { Debug("Time: " + Time.Year.ToString() + "/" + Time.Month.ToString() + "/" +Time.Day.ToString() +": " + Portfolio.TotalPortfolioValue.ToString()); } } if (isRiskon && GOOG_Over_AAPL < SMA_GOOG_Over_AAPL && !isProtectionOn) { RankedBondData = findRanking(BondData); foreach (ETFSymbol ETF in RankedBondData) { if (!data.ContainsKey(ETF.Symbol)) { ETF.totalRank = 10000; } } RankedBondData = RankedBondData.OrderBy(o => o.totalRank).ToList(); int n = 1; foreach (ETFSymbol ETF in RankedBondData) { ETF.totalRankAdjusted = n; n++; } int threshhold1 = BondData.Find(x => x.Symbol == "SHY").totalRankAdjusted; int threshhold2 = BondData.Find(x => x.Symbol == "TLT").totalRankAdjusted; foreach (ETFSymbol ETF in IndustryData.Union(SectorData)) { Liquidate(ETF.Symbol); } if (threshhold1 < threshhold2) { MarketOnCloseOrder("SHY", (int)(Portfolio.Cash/ Securities["SHY"].Close - Portfolio["SHY"].Quantity)); } if (threshhold1 > threshhold2) { MarketOnCloseOrder("TLT", (int)(Portfolio.Cash/ Securities["TLT"].Close - Portfolio["TLT"].Quantity)); } isProtectionOn = true; } isTradeDay = false; foreach (DateTime tradeDay in LastBday) { if (tradeDay.Year == data.Time.Year && tradeDay.Month == data.Time.Month && tradeDay.Day == data.Time.Day) { isTradeDay = true; break; } } if (!isTradeDay) { return; } var delta = data.Time.Subtract(LastRotationTime); if (delta <= RotationInterval) { return; } if ( data.Time.Hour == 15 && data.Time.Minute >= 49) { LastRotationTime = data.Time; if (data.Time.Hour == 16 && data.Time.Minute == 0) { } Debug( "Time: "+Time.Year.ToString() + "/" + Time.Month.ToString() + "/" +Time.Day.ToString() + ":" + Portfolio.TotalPortfolioValue.ToString() + ", Cash: " + Portfolio.Cash.ToString()); if ( GOOG_Over_AAPL > SMA_GOOG_Over_AAPL) { isRiskon = true; isProtectionOn = false; RankedIndustryData = findRanking(IndustryData); foreach (ETFSymbol ETF in RankedIndustryData) { if (!data.ContainsKey(ETF.Symbol)) { ETF.totalRank = 10000; } } RankedIndustryData = RankedIndustryData.OrderBy(o => o.totalRank).ToList(); int n = 1; foreach (ETFSymbol ETF in RankedIndustryData) { ETF.totalRankAdjusted = n; n++; } foreach (ETFSymbol ETF in BondData) { Liquidate(ETF.Symbol); } decimal TotalPortfolioValue = Portfolio.TotalPortfolioValue; foreach (ETFSymbol ETF in RankedIndustryData) { if (ETF.totalRankAdjusted <= 3) { MarketOnCloseOrder(ETF.Symbol, (int)(TotalPortfolioValue /10/ Securities[ETF.Symbol].Close - Portfolio[ETF.Symbol].Quantity)); //Order(ETF.Symbol, (int)(TotalPortfolioValue / 10/ Securities[ETF.Symbol].Close - Portfolio[ETF.Symbol].Quantity), OrderType.Market); } else { Liquidate(ETF.Symbol); } } } else { isRiskon = false; isProtectionOn = false; RankedBondData = findRanking(BondData); foreach (ETFSymbol ETF in RankedBondData) { if (!data.ContainsKey(ETF.Symbol)) { ETF.totalRank = 10000; } } RankedBondData = RankedBondData.OrderBy(o => o.totalRank).ToList(); int n = 1; foreach (ETFSymbol ETF in RankedBondData) { ETF.totalRankAdjusted = n; n++; } int threshhold1 = BondData.Find(x => x.Symbol == "SHY").totalRankAdjusted; int threshhold2 = BondData.Find(x => x.Symbol == "TLT").totalRankAdjusted; foreach (ETFSymbol ETF in IndustryData.Union(SectorData)) { Liquidate(ETF.Symbol); } decimal TotalPortfolioValue = Portfolio.TotalPortfolioValue; foreach (ETFSymbol ETF in RankedBondData) // JJB trade time after 3:55, makert on close { if (ETF.totalRankAdjusted <= 10 && ETF.totalRankAdjusted < Math.Min(threshhold1,threshhold2)) { MarketOnCloseOrder(ETF.Symbol, (int)(TotalPortfolioValue /10/ Securities[ETF.Symbol].Close - Portfolio[ETF.Symbol].Quantity)); } else { Liquidate(ETF.Symbol); } } if (Math.Min(threshhold1,threshhold2)<=10) { if (threshhold1 < threshhold2) { MarketOnCloseOrder("SHY", (int)(Portfolio.Cash/ Securities["SHY"].Close - Portfolio["SHY"].Quantity)); } if (threshhold1 > threshhold2) { MarketOnCloseOrder("TLT", (int)(Portfolio.Cash/ Securities["TLT"].Close - Portfolio["TLT"].Quantity)); } } foreach (ETFSymbol ETF in RankedBondData) { } } } } catch (Exception ex) { Error("OnTradeBar: " + ex.Message + "\r\n\r\n" + ex.StackTrace); } } } }