Overall Statistics |
Total Trades 16 Average Win 0% Average Loss 0% Compounding Annual Return -3.742% Drawdown 3.800% Expectancy 0 Net Profit -1.627% Sharpe Ratio -0.483 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha -0.177 Beta 7.192 Annual Standard Deviation 0.072 Annual Variance 0.005 Information Ratio -0.755 Tracking Error 0.072 Treynor Ratio -0.005 Total Fees $129.09 |
using System.Collections.Concurrent; using System; using System.Collections.Generic; using QuantConnect.Data.Market; using QuantConnect.Data.UniverseSelection; using QuantConnect.Indicators; using QuantConnect.Securities; namespace QuantConnect { /// <summary> /// In this algorithm we demonstrate how to perform some technical analysis as /// part of your coarse fundamental universe selection /// </summary> public class SpringDaySelectionAlgorithm : QCAlgorithm { //Trading vars public string benchmark = "SPY"; //Benchmark to compare results to public decimal max_trading_amount = 250000; //Total Portfolio Cash to spend public int max_long_positions = 25; //Maximum long postions public const int min_price_to_trade = 4; //Minimum price public long min_volume_to_trade = 50000; //Minimum daily volume public float max_amount_per_trade = 0; //The maximium dollar amount to use per trade public float max_target_percent = 0; public float holdings_cnt = 0; private RollingWindow<TradeBar> history; // tolerance to prevent bouncing const decimal Tolerance = 0.01m; private const int Count = 10; // use Buffer+Count to leave a little in cash private const decimal TargetPercent = 0.1m; private SecurityChanges _changes = SecurityChanges.None; // holds our coarse fundamental indicators by symbol private readonly ConcurrentDictionary<Symbol, SelectionData> _averages = new ConcurrentDictionary<Symbol, SelectionData>(); // class used to improve readability of the coarse selection function private class SelectionData { public readonly SimpleMovingAverage Fast; public readonly SimpleMovingAverage Slow; public readonly SimpleMovingAverage Price; public readonly SimpleMovingAverage AverageVolume; public SelectionData() { Fast = new SimpleMovingAverage(10); Slow = new SimpleMovingAverage(45); Price = new SimpleMovingAverage(1); AverageVolume = new SimpleMovingAverage(45); } // computes an object score of how much large the fast is than the slow public decimal ScaledDelta { get { return (Fast - Slow)/((Fast + Slow)/2m); } } // updates the EMA50 and EMA100 indicators, returning true when they're both ready public bool Update(DateTime time, decimal value, decimal volume) { //return Fast.Update(time, value) && Slow.Update(time, value) && Price.Update(time, value) && AverageVolume.Update(time, volume); return Fast.Update(time, value) && Slow.Update(time, value) && Price.Update(time, value); } } /// <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() { UniverseSettings.Leverage = 1.0m; UniverseSettings.Resolution = Resolution.Daily; SetStartDate(2017, 11, 01); SetEndDate(2018, 04, 08); SetCash(max_trading_amount); history = new RollingWindow<TradeBar>(3); max_amount_per_trade = (float) max_trading_amount / (float) max_long_positions; AddUniverse(coarse => { return (from cf in coarse where cf.Price > 5 where cf.Price < 7 where cf.Volume > 250000 let avg = _averages.GetOrAdd(cf.Symbol, sym => new SelectionData()) where avg.Update(cf.EndTime, cf.Price, cf.Volume) // Update returns true when the indicators are ready, so don't accept until they are where cf.Price > avg.Slow where cf.Volume > avg.AverageVolume where cf.HasFundamentalData select cf.Symbol); //select cf.Symbol).Take(Count); }); } //===============Main Entry Point after the Coarse/Fine Selections============== public void OnData(TradeBars data) { int i1= 0; //Get the symbols that made it through the Selection and get their history foreach (var security in _changes.AddedSecurities) { i1++; if (!data.ContainsKey(security.Symbol)) { Debug( String.Format("Missing {0}", security.Symbol )); RemoveSecurity(security.Symbol); //Not Working } else { //acceptableSymbols.Add(symbol); //Symbols with data history.Add(data[security.Symbol]); switch (history.IsReady) { case false: return; case true: if(!security.Invested) { if ( (int)Securities.Count <= max_long_positions) { //If we are at max holdings exit int qty = (int) (max_amount_per_trade / (float) data[security.Symbol].Close); var newTicket = MarketOrder(security.Symbol, qty, asynchronous: true); Debug (String.Format("1Buy {0} {1} - OHLC[{2:0.00}, {3:0.00}, {4:0.00}, {5:0.00}, {6:0},{7:0}]", data.Time.ToString("o"), security.Symbol, data[security.Symbol].Open, data[security.Symbol].High, data[security.Symbol].Low, data[security.Symbol].Close, data[security.Symbol].Volume,qty)); for (int i2 = 0; i2 < 3; i2++) { Debug (String.Format("Hist {0} {1} - OHLC[{2:0.00}, {3:0.00}, {4:0.00}, {5:0.00}, {6:0}]", data.Time.ToString("o"), security.Symbol, history[i2].Open, history[i2].High, history[i2].Low, history[i2].Close, history[i2].Volume)); } } } return; } // End of Case } Debug (String.Format("Total Symbols from Selection: {0} data count: {1}",i1, data.Count)); if (_changes == SecurityChanges.None) return; } } /// Event fired each time the we add/remove securities from the data feed public override void OnSecuritiesChanged(SecurityChanges changes) { _changes = changes; } } }