Overall Statistics |
Total Trades 2011 Average Win 0.71% Average Loss -0.71% Compounding Annual Return 24.147% Drawdown 19.300% Expectancy 0.401 Net Profit 1968.383% Sharpe Ratio 1.068 Probabilistic Sharpe Ratio 60.919% Loss Rate 30% Win Rate 70% Profit-Loss Ratio 1.00 Alpha 0.162 Beta 0.401 Annual Standard Deviation 0.183 Annual Variance 0.033 Information Ratio 0.576 Tracking Error 0.197 Treynor Ratio 0.486 Total Fees $7060.35 |
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using QuantConnect.Data.Fundamental; using QuantConnect.Data.Market; using QuantConnect.Data.UniverseSelection; using QuantConnect.Indicators; using QuantConnect.Orders; using QuantConnect.Orders.Slippage; using QuantConnect.Securities; namespace QuantConnect.Algorithm.CSharp { public class FundamentalAlgorithm : QCAlgorithm { Resolution resolution = Resolution.Daily; int num_screener = 100; int num_stocks = 10; int formation_days = 200; IEnumerable<Symbol> symbols = null; Symbol spy; Symbol ief; bool rebalence_flag; bool first_month_trade_flag; bool trade_flag; public override void Initialize() { SetStartDate(2004, 1, 1); SetEndDate(2018, 1, 1); SetCash(50000); this.spy = AddEquity("SPY", Resolution.Minute).Symbol; this.ief = AddEquity("IEF", resolution).Symbol; UniverseSettings.Resolution = this.resolution; SetUniverseSelection(new FineFundamentalUniverseSelectionModel(CoarseSelectionFunction, FineSelectionFunction)); Schedule.On(DateRules.MonthStart("SPY"), TimeRules.At(0, 0), () => { monthly_rebalance(); }); Schedule.On(DateRules.MonthStart("SPY"), TimeRules.At(10, 0), () => { Rebalance(); }); // rebalance the universe selection once a month this.rebalence_flag = false; // make sure to run the universe selection at the start of the algorithm even it's not the manth start this.first_month_trade_flag = true; this.trade_flag = false; } private void monthly_rebalance() { this.rebalence_flag = true; } private void Rebalance() { var spy_hist = History(this.spy, 120, this.resolution); var spyMeanPrice = spy_hist.Select(bar => bar.Close).ToArray().Average(); var spyPrice = Securities[this.spy].Price; if (spyPrice < spyMeanPrice) { foreach (Symbol symbol in this.Portfolio.Keys) { if (symbol.Value != "IEF") { this.Liquidate(); } } SetHoldings("IEF", 1); Plot("Investments", "IEF", 1); Plot("Investments", "Stocks", 0); return; } else { if (this.symbols == null) return; var chosen = this.calc_return(this.symbols); foreach(Symbol symbol in this.Portfolio.Keys) { if(symbol.Value == "SPY") { continue; } if (!chosen.Contains(symbol)) { this.SetHoldings(symbol, 0); } } if (chosen.Count() > 0) { Plot("Investments", "IEF", 0); Plot("Investments", "Stocks", 1); decimal weight = 0.99m / chosen.Count(); foreach (var symbol in chosen) { this.SetHoldings(symbol, weight); // weight = weight - 0.002m; // if(weight <= 0) // { // break; // } } } } } private IEnumerable<Symbol> calc_return(IEnumerable<Symbol> stocks) { // calculate return for each stock ConcurrentDictionary<Symbol, decimal> returnPerStock = new ConcurrentDictionary<Symbol, decimal>(); foreach (Symbol symbol in stocks) { var hist = History(symbol, this.formation_days, this.resolution); if (hist.Count() > 0) { var last = hist.Last().Close; var first = hist.First().Close; var return1 = (last - first) / first; returnPerStock.AddOrUpdate(symbol, return1); } } var sortedDict = from entry in returnPerStock orderby entry.Value descending select entry; return sortedDict.Select(entry => entry.Key).Take(this.num_stocks); } public IEnumerable<Symbol> CoarseSelectionFunction(IEnumerable<CoarseFundamental> coarse) { if (this.rebalence_flag || this.first_month_trade_flag) { var sortedByDollarVolume = coarse .Where(x => x.HasFundamentalData) .Where(x => x.Price > 5) .OrderByDescending(x => x.DollarVolume); // take the top entries from our sorted collection var numberOfSymbolsCoarse = 200; var top = sortedByDollarVolume.Take(numberOfSymbolsCoarse); // we need to return only the symbol objects return top.Select(x => x.Symbol); }else{ return this.symbols; } } public IEnumerable<Symbol> FineSelectionFunction(IEnumerable<FineFundamental> fine) { if (this.rebalence_flag || this.first_month_trade_flag) { var selected = fine .Where(x => x.EarningReports.BasicAverageShares.ThreeMonths * (x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio) > 2e9m) .OrderByDescending(x => x.ValuationRatios.EVToEBITDA).Take(this.num_screener); // .Where(x => x.CompanyReference.CountryId == "USA") // .Where(x => !x.CompanyReference.IsLimitedPartnership) // .Where(x => !x.CompanyReference.IsREIT) // .Where(x => !x.SecurityReference.IsDepositaryReceipt) // .Where(x => x.SecurityReference.IsPrimaryShare) // .Where(x => x.SecurityReference.ShareClassStatus == "A") // .Where(x => x.SecurityReference.CurrencyId == "USD") // .Where(x => x.SecurityReference.SecurityType == "ST00000001") // .Where(x => x.SecurityReference.ExchangeId != "OTC") // .Where(x => !x.Symbol.Value.Contains("_WI")); this.symbols = selected.Select(x => x.Symbol); this.rebalence_flag = false; this.first_month_trade_flag = false; this.trade_flag = true; return this.symbols; }else{ return this.symbols; } } public override void OnData(Slice data) { } } }