Overall Statistics |
Total Trades 172 Average Win 0.74% Average Loss -1.88% Annual Return 0.324% Drawdown 36.200% Expectancy 0.046 Net Profit 6.647% Sharpe Ratio 0.1 Loss Rate 25% Win Rate 75% Profit-Loss Ratio 0.39 Trade Frequency Weekly trades |
using System; using System.Collections; using System.Collections.Generic; namespace QuantConnect { using QuantConnect.Securities; using QuantConnect.Models; public partial class BasicTemplateAlgorithm : QCAlgorithm, IAlgorithm { string symbol = "MSFT"; bool initialized = false; int numTrackers = 37; decimal[] movingAverages; decimal[] multipliers; bool[,] direction; LinkedList<GainTracker>[,] gainTrackers; decimal[,] crossPrice; int[,] crossCount; int[,] barsSinceCross; int bestI = -1; int bestJ = -1; //int buySize = 100; int slowEMAOffset = 3; int buySize = 500; int minHistoryLength = 60 * 8 * 20; //int maxHistoryLength = 60 * 8 * 120; long time = 0; bool allowShorting = false; int stage = 0; //Initialize the data and resolution you require for your strategy: public override void Initialize() { //Initialize the start, end dates for simulation; cash and data required. SetStartDate(2000, 01, 01); SetEndDate(DateTime.Now.Date.AddDays(-1)); SetCash(30000); //Starting Cash in USD. AddSecurity(SecurityType.Equity, symbol, Resolution.Minute); //Minute, Second or Tick SetRunMode(RunMode.Series); //Series or Parallel for intraday strategies. movingAverages = new decimal[numTrackers]; multipliers = new decimal[numTrackers]; direction = new bool[numTrackers, numTrackers]; crossPrice = new decimal[numTrackers, numTrackers]; crossCount = new int[numTrackers, numTrackers]; barsSinceCross = new int[numTrackers, numTrackers]; gainTrackers = new LinkedList<GainTracker>[numTrackers, numTrackers]; decimal multiplier = 1; for (int i = 0; i < numTrackers; i++) { multiplier *= .7m; multipliers[i] = multiplier; } } //Handle TradeBar Events: a TradeBar occurs on a time-interval (second or minute bars) public override void OnTradeBar(Dictionary<string, TradeBar> data) { decimal lastPrice = data[symbol].Close; decimal fee = Securities[symbol].Model.GetOrderFee(buySize, lastPrice) * 2; time++; if (initialized) { for (int i = 0; i < numTrackers; i++) { movingAverages[i] += (lastPrice - movingAverages[i]) * multipliers[i]; } for (int i = 0; i < numTrackers; i++) { for (int j = i + slowEMAOffset; j < numTrackers; j++) { bool newDirection = movingAverages[i] > movingAverages[j]; if (direction[i, j] != newDirection) { decimal diff = (lastPrice - crossPrice[i, j]) * buySize; if (newDirection) { gainTrackers[i, j].AddLast(new GainTracker(-diff - fee, barsSinceCross[i, j])); } else { gainTrackers[i, j].AddLast(new GainTracker(diff - fee, barsSinceCross[i, j])); } if (i == bestI && j == bestJ) { Debug(bestI + ", " + bestJ); Debug("Fee: " + fee); if (allowShorting) { if (stage == 0) { if (newDirection) { stage = 1; Order(symbol, buySize); } else { stage = 2; Order(symbol, -buySize); } } else { if (newDirection && stage == 2) { stage = 1; Order(symbol, 2 * buySize); } else if (!newDirection && stage == 1) { stage = 2; Order(symbol, -2 * buySize); } } } else { if (newDirection) { if (Portfolio.HoldStock) { Order(symbol, -buySize); } } else { if (!Portfolio.HoldStock) { Order(symbol, buySize); } } } } direction[i, j] = newDirection; crossPrice[i, j] = lastPrice; crossCount[i, j]++; barsSinceCross[i, j] = 1; } else { barsSinceCross[i, j]++; } } } if ((allowShorting || !Portfolio.HoldStock) && time > 9600) { decimal maxGain = .06m; bestI = -1; bestJ = -1; for (int i = 0; i < numTrackers; i++) { for (int j = i + slowEMAOffset; j < numTrackers; j++) { if (gainTrackers[i, j].Count > 0) { int totalDuration = 0; decimal profits = 0; foreach (GainTracker g in gainTrackers[i, j]) { profits += g.profit; totalDuration += g.time; } decimal gainRate = profits / (decimal)totalDuration; if (gainRate > maxGain && totalDuration > minHistoryLength) { maxGain = gainRate; bestI = i; bestJ = j; } if (gainTrackers[i, j].Count > 30) { gainTrackers[i, j].RemoveFirst(); } } } } Debug("Max Gain: " + maxGain); } } else { for (int i = 0; i < numTrackers; i++) { movingAverages[i] = lastPrice; } for (int i = 0; i < numTrackers; i++) { for (int j = i + slowEMAOffset; j < numTrackers; j++) { direction[i, j] = movingAverages[i] > movingAverages[j]; crossPrice[i, j] = lastPrice; barsSinceCross[i, j] = 1; gainTrackers[i, j] = new LinkedList<GainTracker>(); } } initialized = true; } } } public class GainTracker { public decimal profit; public int time; public GainTracker(decimal profit, int time) { this.profit = profit; this.time = time; } } }