/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using QuantConnect.Data; using QuantConnect.Data.Custom; using QuantConnect.Data.Market; using QuantConnect.Indicators; using QuantConnect.Securities.Equity; using QuantConnect.Interfaces; namespace QuantConnect.Algorithm.CSharp { /// /// This algorithm demonstrates the various ways you can call the History function, /// what it returns, and what you can do with the returned values. /// /// /// /// /// public class HistoryAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition { private int _count; private SimpleMovingAverage _spyDailySma; /// /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized. /// public override void Initialize() { SetStartDate(2013, 10, 08); //Set Start Date SetEndDate(2013, 10, 11); //Set End Date SetCash(100000); //Set Strategy Cash // Find more symbols here: http://quantconnect.com/data var SPY = AddSecurity(SecurityType.Equity, "SPY", Resolution.Daily).Symbol; var CME_SP1 = AddData("CHRIS/CME_SP1", Resolution.Daily).Symbol; // specifying the exchange will allow the history methods that accept a number of bars to return to work properly Securities["CHRIS/CME_SP1"].Exchange = new EquityExchange(); // we can get history in initialize to set up indicators and such _spyDailySma = new SimpleMovingAverage(14); // get the last calendar year's worth of SPY data at the configured resolution (daily) var tradeBarHistory = History("SPY", TimeSpan.FromDays(365)); AssertHistoryCount("History(\"SPY\", TimeSpan.FromDays(365))", tradeBarHistory, 250, SPY); // get the last calendar day's worth of SPY data at the specified resolution tradeBarHistory = History("SPY", TimeSpan.FromDays(1), Resolution.Minute); AssertHistoryCount("History(\"SPY\", TimeSpan.FromDays(1), Resolution.Minute)", tradeBarHistory, 390, SPY); // get the last 14 bars of SPY at the configured resolution (daily) tradeBarHistory = History("SPY", 14).ToList(); AssertHistoryCount("History(\"SPY\", 14)", tradeBarHistory, 14, SPY); // get the last 14 minute bars of SPY tradeBarHistory = History("SPY", 14, Resolution.Minute); AssertHistoryCount("History(\"SPY\", 14, Resolution.Minute)", tradeBarHistory, 14, SPY); // we can loop over the return value from these functions and we get TradeBars // we can use these TradeBars to initialize indicators or perform other math foreach (TradeBar tradeBar in tradeBarHistory) { _spyDailySma.Update(tradeBar.EndTime, tradeBar.Close); } // get the last calendar year's worth of quandl data at the configured resolution (daily) var quandlHistory = History("CHRIS/CME_SP1", TimeSpan.FromDays(365)); AssertHistoryCount("History(\"CHRIS/CME_SP1\", TimeSpan.FromDays(365))", quandlHistory, 250, CME_SP1); // get the last 14 bars of SPY at the configured resolution (daily) quandlHistory = History("CHRIS/CME_SP1", 14); AssertHistoryCount("History(\"CHRIS/CME_SP1\", 14)", quandlHistory, 14, CME_SP1); // get the last 14 minute bars of SPY // we can loop over the return values from these functions and we'll get Quandl data // this can be used in much the same way as the tradeBarHistory above _spyDailySma.Reset(); foreach (QuandlFuture quandl in quandlHistory) { _spyDailySma.Update(quandl.EndTime, quandl.Value); } // get the last year's worth of all configured Quandl data at the configured resolution (daily) var allQuandlData = History(TimeSpan.FromDays(365)); AssertHistoryCount("History(TimeSpan.FromDays(365))", allQuandlData, 250, CME_SP1); // get the last 14 bars worth of Quandl data for the specified symbols at the configured resolution (daily) allQuandlData = History(Securities.Keys, 14); AssertHistoryCount("History(Securities.Keys, 14)", allQuandlData, 14, CME_SP1); // NOTE: using different resolutions require that they are properly implemented in your data type, since // Quandl doesn't support minute data, this won't actually work, but if your custom data source has // different resolutions, it would need to be implemented in the GetSource and Reader methods properly //quandlHistory = History("CHRIS/CME_SP1", TimeSpan.FromDays(7), Resolution.Minute); //quandlHistory = History("CHRIS/CME_SP1", 14, Resolution.Minute); //allQuandlData = History(TimeSpan.FromDays(365), Resolution.Minute); //allQuandlData = History(Securities.Keys, 14, Resolution.Minute); //allQuandlData = History(Securities.Keys, TimeSpan.FromDays(1), Resolution.Minute); //allQuandlData = History(Securities.Keys, 14, Resolution.Minute); // get the last calendar year's worth of all quandl data allQuandlData = History(Securities.Keys, TimeSpan.FromDays(365)); AssertHistoryCount("History(Securities.Keys, TimeSpan.FromDays(365))", allQuandlData, 250, CME_SP1); // the return is a series of dictionaries containing all quandl data at each time // we can loop over it to get the individual dictionaries foreach (DataDictionary quandlsDataDictionary in allQuandlData) { // we can access the dictionary to get the quandl data we want var quandl = quandlsDataDictionary["CHRIS/CME_SP1"]; } // we can also access the return value from the multiple symbol functions to request a single // symbol and then loop over it var singleSymbolQuandl = allQuandlData.Get("CHRIS/CME_SP1"); AssertHistoryCount("allQuandlData.Get(\"CHRIS/CME_SP1\")", singleSymbolQuandl, 250, CME_SP1); foreach (QuandlFuture quandl in singleSymbolQuandl) { // do something with 'CHRIS/CME_SP1' quandl data } // we can also access individual properties on our data, this will // get the 'CHRIS/CME_SP1' quandls like above, but then only return the Low properties var quandlSpyLows = allQuandlData.Get("CHRIS/CME_SP1", "Low"); AssertHistoryCount("allQuandlData.Get(\"CHRIS/CME_SP1\", \"Low\")", quandlSpyLows, 250); foreach (decimal low in quandlSpyLows) { // do something with each low value } // sometimes it's necessary to get the history for many configured symbols // request the last year's worth of history for all configured symbols at their configured resolutions var allHistory = History(TimeSpan.FromDays(365)); AssertHistoryCount("History(TimeSpan.FromDays(365))", allHistory, 250, SPY, CME_SP1); // request the last days's worth of history at the minute resolution allHistory = History(TimeSpan.FromDays(1), Resolution.Minute); AssertHistoryCount("History(TimeSpan.FromDays(1), Resolution.Minute)", allHistory, 391, SPY, CME_SP1); // request the last 100 bars for the specified securities at the configured resolution allHistory = History(Securities.Keys, 100); AssertHistoryCount("History(Securities.Keys, 100)", allHistory, 100, SPY, CME_SP1); // request the last 100 minute bars for the specified securities allHistory = History(Securities.Keys, 100, Resolution.Minute); AssertHistoryCount("History(Securities.Keys, 100, Resolution.Minute)", allHistory, 101, SPY, CME_SP1); // request the last calendar years worth of history for the specified securities allHistory = History(Securities.Keys, TimeSpan.FromDays(365)); AssertHistoryCount("History(Securities.Keys, TimeSpan.FromDays(365))", allHistory, 250, SPY, CME_SP1); // we can also specify the resolution allHistory = History(Securities.Keys, TimeSpan.FromDays(1), Resolution.Minute); AssertHistoryCount("History(Securities.Keys, TimeSpan.FromDays(1), Resolution.Minute)", allHistory, 391, SPY, CME_SP1); // if we loop over this allHistory, we get Slice objects foreach (Slice slice in allHistory) { // do something with each slice, these will come in time order // and will NOT have auxilliary data, just price data and your custom data // if those symbols were specified } // we can access the history for individual symbols from the all history by specifying the symbol // the type must be a trade bar! tradeBarHistory = allHistory.Get("SPY"); AssertHistoryCount("allHistory.Get(\"SPY\")", tradeBarHistory, 390, SPY); // we can access all the closing prices in chronological order using this get function var closeHistory = allHistory.Get("SPY", Field.Close); AssertHistoryCount("allHistory.Get(\"SPY\", Field.Close)", closeHistory, 390); foreach (decimal close in closeHistory) { // do something with each closing value in order } // we can convert the close history into your normal double array (double[]) using the ToDoubleArray method double[] doubleArray = closeHistory.ToDoubleArray(); // for the purposes of regression testing, we're explicitly requesting history // using the universe symbols. Requests for universe symbols are filtered out // and never sent to the history provider. var universeSecurityHistory = History(UniverseManager.Keys, TimeSpan.FromDays(10)).ToList(); if (universeSecurityHistory.Count != 0) { throw new Exception("History request for universe symbols incorrectly returned data. " + "These requests are intended to be filtered out and never sent to the history provider."); } } /// /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. /// /// Slice object keyed by symbol containing the stock data public override void OnData(Slice data) { _count++; if (_count > 5) { throw new Exception("Invalid number of bars arrived. Expected exactly 5"); } if (!Portfolio.Invested) { SetHoldings("SPY", 1); Debug("Purchased Stock"); } } private void AssertHistoryCount(string methodCall, IEnumerable history, int expected, params Symbol[] expectedSymbols) { history = history.ToList(); var count = history.Count(); if (count != expected) { throw new Exception(methodCall + " expected " + expected + ", but received " + count); } IEnumerable unexpectedSymbols = null; if (typeof(T) == typeof(Slice)) { var slices = (IEnumerable) history; unexpectedSymbols = slices.SelectMany(slice => slice.Keys) .Distinct() .Where(sym => !expectedSymbols.Contains(sym)) .ToList(); } else if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(DataDictionary<>)) { if (typeof(T).GetGenericArguments()[0] == typeof(QuandlFuture)) { var dictionaries = (IEnumerable>) history; unexpectedSymbols = dictionaries.SelectMany(dd => dd.Keys) .Distinct() .Where(sym => !expectedSymbols.Contains(sym)) .ToList(); } } else if (typeof(IBaseData).IsAssignableFrom(typeof(T))) { var slices = (IEnumerable)history; unexpectedSymbols = slices.Select(data => data.Symbol) .Distinct() .Where(sym => !expectedSymbols.Contains(sym)) .ToList(); } else if (typeof(T) == typeof(decimal)) { // if the enumerable doesn't contain symbols then we can't assert that certain symbols exist // this case is used when testing data dictionary extensions that select a property value, // such as dataDictionaries.Get("MySymbol", "MyProperty") => IEnumerable return; } if (unexpectedSymbols == null) { throw new Exception("Unhandled case: " + typeof(T).GetBetterTypeName()); } var unexpectedSymbolsString = string.Join(" | ", unexpectedSymbols); if (!string.IsNullOrWhiteSpace(unexpectedSymbolsString)) { throw new Exception($"{methodCall} contains unexpected symbols: {unexpectedSymbolsString}"); } } /// /// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm. /// public bool CanRunLocally { get; } = true; /// /// This is used by the regression test system to indicate which languages this algorithm is written in. /// public Language[] Languages { get; } = { Language.CSharp, Language.Python }; /// /// This is used by the regression test system to indicate what the expected statistics are from running the algorithm /// public Dictionary ExpectedStatistics => new Dictionary { {"Total Trades", "1"}, {"Average Win", "0%"}, {"Average Loss", "0%"}, {"Compounding Annual Return", "359.952%"}, {"Drawdown", "1.100%"}, {"Expectancy", "0"}, {"Net Profit", "1.686%"}, {"Sharpe Ratio", "4.502"}, {"Loss Rate", "0%"}, {"Win Rate", "0%"}, {"Profit-Loss Ratio", "0"}, {"Alpha", "0"}, {"Beta", "77.786"}, {"Annual Standard Deviation", "0.191"}, {"Annual Variance", "0.036"}, {"Information Ratio", "4.445"}, {"Tracking Error", "0.191"}, {"Treynor Ratio", "0.011"}, {"Total Fees", "$3.26"} }; /// /// Custom quandl data type for setting customized value column name. Value column is used for the primary trading calculations and charting. /// public class QuandlFuture : Quandl { /// /// Initializes a new instance of the class. /// public QuandlFuture() : base(valueColumnName: "Settle") { } } } }