Overall Statistics |
Total Trades 4992 Average Win 0.06% Average Loss -0.04% Compounding Annual Return -31.518% Drawdown 45.400% Expectancy -0.31 Net Profit -45.117% Sharpe Ratio -8.655 Loss Rate 73% Win Rate 27% Profit-Loss Ratio 1.6 Alpha -0.38 Beta 0.019 Annual Standard Deviation 0.043 Annual Variance 0.002 Information Ratio -4.587 Tracking Error 0.128 Treynor Ratio -19.324 Total Fees $27757.59 |
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; namespace QuantConnect { class BuyLowStrategy { // Fields //private int symbolsN; private int runsPerDay; private int previousDaysN; private Dictionary<string, bool> newDay = new Dictionary<string,bool>(); private Dictionary<string, decimal> previousValue = new Dictionary<string, decimal>(); private Dictionary<string, DateTime> previousValueDate = new Dictionary<string, DateTime>(); private Dictionary<string, decimal> accumulatedRun = new Dictionary<string, decimal>(); private Dictionary<string, decimal> valuePrevToRun = new Dictionary<string, decimal>(); private Dictionary<string, List<decimal>> intraDayRuns = new Dictionary<string, List<decimal>>(); private Dictionary<string, Queue<decimal>> dailyDownwardRuns = new Dictionary<string, Queue<decimal>>(); private Dictionary<string, Queue<decimal>> dailyUpwardRuns = new Dictionary<string, Queue<decimal>>(); private Dictionary<string, decimal> previousDaysDownwardRuns = new Dictionary<string, decimal>(); private Dictionary<string, decimal> previousDaysUpwardRuns = new Dictionary<string, decimal>(); private Dictionary<string, bool> isReady = new Dictionary<string, bool>(); private Dictionary<string, bool> turnAround = new Dictionary<string, bool>(); private Dictionary<string, int> orderSignal = new Dictionary<string, int>(); public Dictionary<string, bool> IsReady { get { return isReady; } } public Dictionary<string, bool> TurnAround { get { return turnAround; } } public Dictionary<string, int> OrderSignal { get { return orderSignal; } } // Constructor public BuyLowStrategy(string[] symbols, int PreviousDaysN, int RunsPerDay) { //this.symbolsN = symbols.Length; this.previousDaysN = PreviousDaysN; this.runsPerDay = RunsPerDay; foreach (string symbol in symbols) { intraDayRuns.Add(symbol, new List<decimal>()); dailyDownwardRuns.Add(symbol, new Queue<decimal>()); dailyUpwardRuns.Add(symbol, new Queue<decimal>()); previousValueDate.Add(symbol, new DateTime()); valuePrevToRun.Add(symbol, new decimal()); previousValue.Add(symbol, new decimal()); accumulatedRun.Add(symbol, new decimal()); isReady.Add(symbol, false); turnAround.Add(symbol, false); previousDaysDownwardRuns.Add(symbol, new decimal()); previousDaysUpwardRuns.Add(symbol, new decimal()); orderSignal.Add(symbol, 0); newDay[symbol] = true; } } // Add public void AddSerieValue(string symbol, DateTime timeStamp, decimal serieValue) { bool sameDay; DateTime actualValueDate = timeStamp.Date; if (newDay[symbol]) { // Day initialization previousValueDate[symbol] = actualValueDate; valuePrevToRun[symbol] = serieValue; previousValue[symbol] = serieValue; accumulatedRun[symbol] = 0; //isReady[symbol] = false; turnAround[symbol] = false; newDay[symbol] = false; } sameDay = actualValueDate == previousValueDate[symbol].Date; if (sameDay) { DayTripper(timeStamp, symbol, serieValue); // I quickly run out of ideas for good method's names. } else { DayEnd(symbol); newDay[symbol] = true; } } private void DayTripper(DateTime timeStamp, string symbol, decimal serieValue) { decimal valueDiff; decimal brokenRun; decimal previousAccum = accumulatedRun[symbol]; valueDiff = serieValue - previousValue[symbol]; if (valueDiff * previousAccum >= 0) { accumulatedRun[symbol] = previousAccum + valueDiff; turnAround[symbol] = false; } else { accumulatedRun[symbol] = valueDiff; turnAround[symbol] = true; brokenRun = previousAccum / valuePrevToRun[symbol]; valuePrevToRun[symbol] = previousValue[symbol]; intraDayRuns[symbol].Add(brokenRun); CheckOrders(symbol, brokenRun); } previousValue[symbol] = serieValue; previousValueDate[symbol] = timeStamp; } private void DayEnd(string symbol) { decimal dayMeanDownwardRun; decimal dayMeanUpwardRun; dayMeanDownwardRun = (from run in intraDayRuns[symbol] where run < 0 orderby run ascending select run).Take(runsPerDay).Average(); dayMeanUpwardRun = (from run in intraDayRuns[symbol] where run > 0 orderby run descending select run).Take(runsPerDay).Average(); dailyDownwardRuns[symbol].Enqueue(dayMeanDownwardRun); dailyUpwardRuns[symbol].Enqueue(dayMeanUpwardRun); intraDayRuns[symbol].Clear(); if (dailyDownwardRuns[symbol].Count == previousDaysN) isReady[symbol] = true; if (dailyDownwardRuns[symbol].Count > previousDaysN) { dailyDownwardRuns[symbol].Dequeue(); dailyUpwardRuns[symbol].Dequeue(); } previousDaysDownwardRuns[symbol] = dailyDownwardRuns[symbol].Average(); previousDaysUpwardRuns[symbol] = dailyUpwardRuns[symbol].Average(); } private void CheckOrders(string symbol, decimal brokenRun) { if (this.isReady[symbol]) { orderSignal[symbol] = 0; // Do nothing if (brokenRun < 0 && brokenRun < previousDaysDownwardRuns[symbol]) { // Long order orderSignal[symbol] = 1; } else if (brokenRun > 0 && brokenRun > previousDaysUpwardRuns[symbol]) { // Short order orderSignal[symbol] = -1; } } } } }
using System; using System.Collections.Generic; using QuantConnect.Indicators; using QuantConnect.Data.Market; namespace QuantConnect { /// <summary> /// Basic template algorithm simply initializes the date range and cash /// </summary> public class IntradayBuyLow : QCAlgorithm { static string[] symbols = { "AAPL", "GOOGL", "IBM", "MSFT"}; BuyLowStrategy Strategy = new BuyLowStrategy(symbols, 5, 4); Dictionary<string, ExponentialMovingAverage> ema = new Dictionary<string, ExponentialMovingAverage>(); /// <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() { SetStartDate(2012, 1, 1); //Set Start Date SetEndDate(2015, 5, 15); //Set End Date SetCash(100000); //Set Strategy Cash // Find more symbols here: http://quantconnect.com/data foreach (string symbol in symbols) { AddSecurity(SecurityType.Equity, symbol, Resolution.Minute); ema.Add(symbol, EMA(symbol, 5, Resolution.Minute)); } } /// <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) { foreach (string symbol in symbols) { if (!ema[symbol].IsReady) return; Strategy.AddSerieValue(symbol, Time, ema[symbol]); if (Strategy.IsReady[symbol]) { if (Portfolio[symbol].HoldStock) { if (Strategy.TurnAround[symbol]) { Liquidate(symbol); } } else { if (Strategy.OrderSignal[symbol] != 0) { EntryAndSetStopLoss(symbol, Strategy.OrderSignal[symbol]); } } } } } private void EntryAndSetStopLoss(string symbol, int signal) { decimal stopLossPrice; int orderSize = SetOrderSize(signal); SetHoldings(symbol, 0.25*signal); //MarketOrder(symbol, orderSize); //Debug((signal > 0) ? "Buy " : "Sell " + orderSize.ToString() + " " // + symbol + " shares @ $" + Portfolio[symbol].HoldingsCost); //stopLossPrice = Portfolio[symbol].HoldingsCost * SetStopLossCoef(); //StopMarketOrder(symbol, -orderSize, stopLossPrice); //Debug("Stop loss order @ $" + stopLossPrice.ToString()); } private int SetOrderSize(int signal) { // TO DO: Sizing model return 100 * signal; } private decimal SetStopLossCoef() { return 0.95m; } } }