Overall Statistics |
Total Trades 1 Average Win 0% Average Loss 0% Compounding Annual Return -1.247% Drawdown 0.000% Expectancy 0 Net Profit -0.011% Sharpe Ratio -9.165 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0.005 Beta -0.994 Annual Standard Deviation 0.001 Annual Variance 0 Information Ratio -12.72 Tracking Error 0.002 Treynor Ratio 0.009 Total Fees $1.00 |
namespace QuantConnect { /// <summary> /// Cloned from https://github.com/QuantConnect/Lean/blob/master/Algorithm.CSharp/MultipleSymbolConsolidationAlgorithm.cs /// </summary> /* Things to do: 1. Add two or more symbols to be looked at. 2. Get the last 10 prices for each 2 hour period. This could be over multiple days, ignore weekend and holidays. 3. Warmup does not seem to be working 4. In the documentation I saw a line for RegisterIndicator. Is this not required? 5. How would I used Consolidators with long and short SMA. 6. How would I used Consolidators withe multiple indicators - SMA, RSI - Long and short for each 7. The "Bar" has two values Time and EndTime. The data provided is for which time? 8. Could the SMA be defined with symbolData.SMA = SMA(symbolData.Symbol, SimpleMovingAveragePeriod, ResolutionPeriod); 9. */ /* Errors: */ public class TestConsolidatedIndicator : QCAlgorithm { private const int BarPeriodValue = 2; /// <summary> /// This is the period of bars we'll be creating /// </summary> public readonly Resolution ResolutionPeriod = Resolution.Hour; /// <summary> /// This is the period of bars we'll be creating /// </summary> //public readonly TimeSpan BarPeriod; //= GetBarPeriod(); /// <summary> /// This is the period of our sma indicators /// </summary> public readonly int SimpleMovingAveragePeriod = 3; /// <summary> /// This is the number of consolidated bars we'll hold in symbol data for reference /// </summary> public readonly int RollingWindowSize = 5; /// <summary> /// Holds all of our data keyed by each symbol /// </summary> public readonly Dictionary<string, SymbolData> Data = new Dictionary<string, SymbolData>(); /// <summary> /// Contains all of our equity symbols /// </summary> public readonly IReadOnlyList<string> EquitySymbols = new List<string> { // "AAPL", // "SPY", "IBM" }; /// <summary> /// This is the period of bars we'll be creating /// </summary> private TimeSpan GetBarPeriod() { switch (ResolutionPeriod) { case Resolution.Minute: return TimeSpan.FromMinutes(BarPeriodValue); case Resolution.Hour: return TimeSpan.FromHours(BarPeriodValue); case Resolution.Daily: return TimeSpan.FromDays(BarPeriodValue); default: throw new ArgumentOutOfRangeException(); } } /// <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(1998, 01, 03); // Set Start Date SetEndDate(1998, 1, 5); // Set End Date SetCash(10000); // Set Strategy Cash SetWarmUp(RollingWindowSize); // Happens after Initalize is done. // initialize our equity data foreach (var symbol in EquitySymbols) { var equity = AddEquity(symbol, ResolutionPeriod); Data.Add(symbol, new SymbolData(equity.Symbol, GetBarPeriod(), RollingWindowSize)); } // loop through all our symbols and request data subscriptions and initialize indicators foreach (var kvp in Data) { // this is required since we're using closures below, for more information // see: http://stackoverflow.com/questions/14907987/access-to-foreach-variable-in-closure-warning var symbolData = kvp.Value; // define a consolidator to consolidate data for this symbol on the requested period var consolidator = symbolData.Symbol.SecurityType == SecurityType.Equity ? (IDataConsolidator)new TradeBarConsolidator(GetBarPeriod()) : (IDataConsolidator)new QuoteBarConsolidator(GetBarPeriod()); // define our indicator symbolData.SMA = new SimpleMovingAverage(CreateIndicatorName(symbolData.Symbol, "SMA" + SimpleMovingAveragePeriod, ResolutionPeriod), SimpleMovingAveragePeriod); //symbolData.SMA = SMA(symbolData.Symbol, SimpleMovingAveragePeriod, ResolutionPeriod); // wire up our consolidator to update the indicator consolidator.DataConsolidated += (sender, baseData) => { // 'bar' here is our newly consolidated data var bar = (IBaseDataBar)baseData; // update the indicator symbolData.SMA.Update(bar.Time, bar.Close); // we're also going to add this bar to our rolling window so we have access to it later symbolData.Bars.Add(bar); }; consolidator.DataConsolidated += HandleConsolidatedData; // HERE: Need this // we need to add this consolidator so it gets auto updates SubscriptionManager.AddConsolidator(symbolData.Symbol, consolidator); } // Debug("Is the warmup done?"); } public void HandleConsolidatedData(object pSender, IBaseData pBaseData) { //if (IsWarmingUp) return; var vMethodName = "HandleConsolidatedData"; LogMethodStart(vMethodName); // loop through each symbol in our structure foreach (var symbolData in Data.Values) { // this check proves that this symbol was JUST updated prior to this OnData function being called if (symbolData.IsReady && symbolData.WasJustUpdated(Time)) { LogMethodStart(vMethodName + " - " + symbolData.Symbol); foreach(var bar in symbolData.Bars) { var message = String.Format("{4} - Time: {0:ddd} {0} ; EndTime: {1:ddd} {1} ; Value: {2} ; Price: {3}", bar.Time, bar.EndTime, bar.Value, bar.Price, vMethodName); // Debug(bar.ToString()); Debug(message); } if (!Portfolio[symbolData.Symbol].Invested) { MarketOrder(symbolData.Symbol, 1); } } } } /// <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 override void OnData(Slice data) // public void OnData(TradeBars data) { var vMethodName = "OnData"; if (IsWarmingUp) return; LogMethodStart(vMethodName); // loop through each symbol in our structure foreach (var symbolData in Data.Values) { // this check proves that this symbol was JUST updated prior to this OnData function being called if (symbolData.IsReady && symbolData.WasJustUpdated(Time)) { // LogMethodStart(vMethodName + " - " + symbolData.Symbol); // foreach(var bar in symbolData.Bars) // { // var message = String.Format("{4} - Time: {0:ddd} {0} ; EndTime: {1:ddd} {1} ; Value: {2} ; Price: {3}", bar.Time, bar.EndTime, bar.Value, bar.Price, vMethodName); // // Debug(bar.ToString()); // Debug(message); // } if (!Portfolio[symbolData.Symbol].Invested) { MarketOrder(symbolData.Symbol, 1); } } } } /// <summary> /// End of a trading day event handler. This method is called at the end of the algorithm day (or multiple times if trading multiple assets). /// </summary> /// <remarks>Method is called 10 minutes before closing to allow user to close out position.</remarks> public override void OnEndOfDay() { LogMethodStart("OnEndOfDay"); int i = 0; foreach (var kvp in Data.OrderBy(x => x.Value.Symbol)) { // we have too many symbols to plot them all, so plot ever other if (kvp.Value.IsReady && ++i%2 == 0) { Plot(kvp.Value.Symbol.ToString(), kvp.Value.SMA); } } } #region Log Method Start & End private void LogMethodStart(string pMethodName) { LogMethod(pMethodName); } private void LogMethodEnd(string pMethodName) { LogMethod(pMethodName, false); } private void LogMethod(string pMethodName, bool pIsStart = true) { var vState = pIsStart ? "Start" : "End"; var vMessage = String.Format("Method: {0} {1} - {2:MM/dd/yy H:mm:ss:fff}", pMethodName, vState, Time); LogIt(vMessage); } #endregion Log Method Start & End private void LogIt(string pMessage) { //Debug(pMessage); Log(pMessage); } /// <summary> /// Contains data pertaining to a symbol in our algorithm /// </summary> public class SymbolData { /// <summary> /// This symbol the other data in this class is associated with /// </summary> public readonly Symbol Symbol; /// <summary> /// A rolling window of data, data needs to be pumped into Bars by using Bars.Update( tradeBar ) and /// can be accessed like: /// mySymbolData.Bars[0] - most first recent piece of data /// mySymbolData.Bars[5] - the sixth most recent piece of data (zero based indexing) /// </summary> public readonly RollingWindow<IBaseDataBar> Bars; /// <summary> /// The period used when population the Bars rolling window. /// </summary> public readonly TimeSpan BarPeriod; /// <summary> /// The simple moving average indicator for our symbol /// </summary> public SimpleMovingAverage SMA; /// <summary> /// Initializes a new instance of SymbolData /// </summary> public SymbolData(Symbol symbol, TimeSpan barPeriod, int windowSize) { Symbol = symbol; BarPeriod = barPeriod; Bars = new RollingWindow<IBaseDataBar>(windowSize); } /// <summary> /// Returns true if all the data in this instance is ready (indicators, rolling windows, ect...) /// </summary> public bool IsReady { get { return Bars.IsReady && SMA.IsReady; } } /// <summary> /// Returns true if the most recent trade bar time matches the current time minus the bar's period, this /// indicates that update was just called on this instance /// </summary> /// <param name="current">The current algorithm time</param> /// <returns>True if this instance was just updated with new data, false otherwise</returns> public bool WasJustUpdated(DateTime current) { return Bars.Count > 0 && Bars[0].Time == current - this.BarPeriod; } public void ShowBars() { Console.WriteLine("Show Bars for: " + Symbol.ToString()); foreach(var bar in Bars) { Console.WriteLine(bar.ToString()); } } } } }