Overall Statistics |
Total Trades 3067 Average Win 0.56% Average Loss -0.36% Compounding Annual Return 18.821% Drawdown 35.300% Expectancy 0.470 Net Profit 1256.789% Sharpe Ratio 1.014 Probabilistic Sharpe Ratio 52.411% Loss Rate 43% Win Rate 57% Profit-Loss Ratio 1.58 Alpha 0.157 Beta -0.042 Annual Standard Deviation 0.151 Annual Variance 0.023 Information Ratio 0.302 Tracking Error 0.228 Treynor Ratio -3.616 Total Fees $19149.02 |
/* * 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 QuantConnect.Data; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; using QuantConnect.Data.Market; using QuantConnect.Data.UniverseSelection; using QuantConnect.Indicators; using QuantConnect.Data.Custom; using QuantConnect.Orders; using QuantConnect.Securities; using QuantConnect.Data.Consolidators; namespace QuantConnect.Algorithm.CSharp { public class StockRankAlgorithm : QCAlgorithm { // algorythm settings const Resolution _algo_resolution = Resolution.Daily; private ExponentialMovingAverage _spyMovingAverage; private const string Spy = "SPY"; private int _trendfilter = 200; public const decimal _startingcash = 100000m; public const decimal _maxLeverage = 1.0m; public const decimal _maxNumHoldings = 25m; public const decimal _positionweight = _maxLeverage/_maxNumHoldings; private bool flag1 = true; private bool flag2 = false; private int flag3 = 0; private int _securitiesnum = 0; private SecurityChanges _changes = SecurityChanges.None; public DateTime _startdate = new DateTime(2005, 1, 1); // public DateTime _enddate = new DateTime(2014, 11, 23); //public DateTime _startdate = new DateTime(2015, 1, 1); //public DateTime _startdate = DateTime.Now.Date.AddDays(-120); public DateTime _enddate = DateTime.Now.Date.AddDays(-1); //public DateTime _enddate = new DateTime(2011, 1, 1); // sort the data by daily dollar volume and take the top 'NumberOfSymbolsCoarse' public IEnumerable<Symbol> CoarseSelectionFunction(IEnumerable<CoarseFundamental> coarse) { if (flag1) { var hasmorningstar = from x in coarse where (x.HasFundamentalData) orderby x.DollarVolume descending select x.Symbol; // we need to return only the symbol objects return hasmorningstar.Take(1000); } else { return Enumerable.Empty<Symbol>(); } } // sort the data by P/E ratio and take the top 'NumberOfSymbolsFine' public IEnumerable<Symbol> FineSelectionFunction(IEnumerable<FineFundamental> fine) { if (flag1) { flag1 = false; flag2 = true; ConcurrentDictionary<Symbol, IndicatorBase<IndicatorDataPoint>> averages = new ConcurrentDictionary<Symbol, IndicatorBase<IndicatorDataPoint>>(); // find piatroski score var piatroskiscore = from x in fine where x.SecurityReference.SecurityType == "ST00000001" && x.SecurityReference.IsPrimaryShare where !x.SecurityReference.IsDepositaryReceipt where x.AssetClassification.MorningstarIndustryGroupCode != MorningstarSectorCode.FinancialServices where x.AssetClassification.MorningstarIndustryGroupCode != MorningstarSectorCode.Utilities // where (x.EarningReports.BasicAverageShares.ThreeMonths * (x.EarningReports.BasicEPS.TwelveMonths*x.ValuationRatios.PERatio) > 300000000) //&& x.EarningReports.BasicAverageShares.ThreeMonths * (x.EarningReports.BasicEPS.TwelveMonths*x.ValuationRatios.PERatio) < 2000000000) let fs = FScore( x.FinancialStatements.IncomeStatement.NetIncome.TwelveMonths, x.FinancialStatements.CashFlowStatement.CashFlowFromContinuingOperatingActivities.TwelveMonths, x.OperationRatios.ROA.ThreeMonths, x.OperationRatios.ROA.OneYear, x.FinancialStatements.BalanceSheet.ShareIssued.ThreeMonths, x.FinancialStatements.BalanceSheet.ShareIssued.TwelveMonths, x.OperationRatios.GrossMargin.ThreeMonths, x.OperationRatios.GrossMargin.OneYear, x.OperationRatios.LongTermDebtEquityRatio.ThreeMonths, x.OperationRatios.LongTermDebtEquityRatio.OneYear, // fix need last year x.OperationRatios.CurrentRatio.ThreeMonths, x.OperationRatios.CurrentRatio.OneYear, // fix need last year x.OperationRatios.AssetsTurnover.ThreeMonths, x.OperationRatios.AssetsTurnover.OneYear // fix need last year ) where (fs >= 6) //orderby fs descending let avg = averages.GetOrAdd(x.Symbol, sym => WarmUpIndicator(x.Symbol, new MomentumPercent(90), Resolution.Daily)) // Update returns true when the indicators are ready, so don't accept until they are where avg.Update(x.EndTime, x.Price) // only pick symbols who have positive slopes [Absolute Momentum] where avg > 0m // prefer symbols with a larger slope orderby (avg) descending select x; // take the top entries from our sorted collection var topFine = piatroskiscore.Take((int)_maxNumHoldings); _securitiesnum = topFine.Count(); flag3++; //Debug("Found " + topFine.Count() + " possibilities"); // foreach (var s in topFine) // { // Debug(s.ToString()); // } // we need to return only the symbol objects return topFine.Select(x => x.Symbol); } else { return Enumerable.Empty<Symbol>(); } } // Initialize the data and resolution you require for your strategy: public override void Initialize() { SetStartDate(_startdate); SetEndDate(_enddate); // don't do any margin stuff SetBrokerageModel(Brokerages.BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin); var spy = AddEquity(Spy); AddEquity("TLT"); SetBenchmark(spy.Symbol); _spyMovingAverage = EMA(spy.Symbol, _trendfilter, Resolution.Daily); //Warm up indicator //IEnumerable<TradeBar> history = History(spy.Symbol, _trendfilter, Resolution.Daily); //foreach (TradeBar tradeBar in history) //{ // _spyMovingAverage.Update(tradeBar.EndTime, tradeBar.Close); //} //set warm up algorithm to avoid premature trading SetWarmUp(_trendfilter); EnableAutomaticIndicatorWarmUp = true; //Cash allocation SetCash(_startingcash); UniverseSettings.Resolution = _algo_resolution; // this add universe method accepts two parameters: // - coarse selection function: accepts an IEnumerable<CoarseFundamental> and returns an IEnumerable<Symbol> // - fine selection function: accepts an IEnumerable<FineFundamental> and returns an IEnumerable<Symbol> AddUniverse(CoarseSelectionFunction, FineSelectionFunction); Schedule.On(DateRules.MonthStart(spy.Symbol) , TimeRules.AfterMarketOpen(spy.Symbol), Rebalancing); } public override void OnData(Slice slice) { if (flag3 > 0) { if (flag2) { flag2 = false; // //# if we have no changes, do nothing if (_changes == SecurityChanges.None) return; //# liquidate removed securities foreach (Security security in _changes.RemovedSecurities) { if (security.Invested) Liquidate(security.Symbol); Debug("Liquidated Stock: " + security.Symbol.Value); } decimal diff = _maxNumHoldings - _securitiesnum; SetHoldings("TLT", _positionweight*diff); if (Securities[Spy].Price > _spyMovingAverage) { foreach (Security security in _changes.AddedSecurities) { if (security.Symbol.Value.Equals("SPY")) continue; if (security.Symbol.Value.Equals("TLT")) continue; SetHoldings(security.Symbol, _positionweight); Debug("Purchased Stock: " + security.Symbol.Value); } } _changes = SecurityChanges.None; if (Portfolio.TotalPortfolioValue > 0) { decimal accountLeverage = Portfolio.TotalAbsoluteHoldingsCost / Portfolio.TotalPortfolioValue; decimal bondLeverage = (Portfolio["TLT"].Quantity*Portfolio["TLT"].Price) / Portfolio.TotalPortfolioValue; Plot("Leverage", "Leverage", accountLeverage); Plot("Leverage", "bondLeverage", bondLeverage); Plot("Memory", "memusage", (float)GC.GetTotalMemory(false)); } } } } //# this event fires whenever we have changes to our universe public override void OnSecuritiesChanged(SecurityChanges changes) { _changes = changes; if (changes.AddedSecurities.Count > 0) { Debug("Securities added: " + string.Join(",", changes.AddedSecurities.Select(x => x.Symbol.Value))); } if (changes.RemovedSecurities.Count > 0) { Debug("Securities removed: " + string.Join(",", changes.RemovedSecurities.Select(x => x.Symbol.Value))); } } public void Rebalancing() { //can rebalance every month if (Time.Month % 1 == 0) //can rebalance once a year in a particular month //if (Time.Month == 5) //can rebalance every quarter //if (Time.Month % 3 == 0) //can rebalance every two months //if (Time.Month % 2 == 0) { flag1 = true; } } // calculate the f-score private int FScore( decimal netincome, decimal operating_cashflow, decimal roa_current, decimal roa_past, decimal issued_current, decimal issued_past, decimal grossm_current, decimal grossm_past, decimal longterm_current, decimal longterm_past, decimal curratio_current, decimal curratio_past, decimal assetturn_current, decimal assetturn_past ) { int fscore = 0; fscore += (roa_current > 0m ? 1 : 0 ); // return on assets is positive fscore += ( operating_cashflow > 0m ? 1 : 0 ); // operating cashflow in current year is positive fscore += ( roa_current >= roa_past ? 1 : 0 ); // roa has increased since last Time fscore += ( operating_cashflow > roa_current ? 1 : 0 ); // cashflow from current operations are greater than roa fscore += ( longterm_current <= longterm_past ? 1 : 0 ); // a decrease in the long term debt ratio fscore += ( curratio_current >= curratio_past ? 1 : 0 ); // an increase in the current ratio fscore += ( issued_current <= issued_past ? 1 : 0 ); // no new shares have been issued fscore += ( grossm_current >= grossm_past ? 1 : 0 ); // an increase in gross margin fscore += ( assetturn_current >= assetturn_past ? 1 : 0 ); // a higher asset turnover ratio // Debug("<<<<<<"); //Debug("f-score :" +fscore); // Debug("roa current : " + roa_current); // Debug("operating cashflow : " + operating_cashflow); // Debug("roa current : " + roa_current + " past : " + roa_past); // Debug("operating cashflow : " + operating_cashflow ); // Debug("longterm_current : " + longterm_current + " past : " + longterm_past); // Debug("curratio_current : " + curratio_current + " past : " + curratio_past); // Debug("issued current : " + issued_current + " : past " + issued_past); // Debug("grossm current : " + grossm_current + " : past " + grossm_past); // Debug("assetturn_current : " + assetturn_current + " : " + assetturn_past); return fscore; } } }