/* * 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 QuantConnect.Util; using System.Collections.Generic; using System.Linq; using QuantConnect.Data; 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 _dailySma; /// /// 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 IBM = AddData("IBM", Resolution.Daily).Symbol; // specifying the exchange will allow the history methods that accept a number of bars to return to work properly Securities["IBM"].Exchange = new EquityExchange(); // we can get history in initialize to set up indicators and such _dailySma = 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) { _dailySma.Update(tradeBar.EndTime, tradeBar.Close); } // get the last calendar year's worth of IBM data at the configured resolution (daily) var customDataHistory = History("IBM", TimeSpan.FromDays(365)); AssertHistoryCount("History(\"IBM\", TimeSpan.FromDays(365))", customDataHistory, 250, IBM); // get the last 14 bars of IBM at the configured resolution (daily) customDataHistory = History("IBM", 14); AssertHistoryCount("History(\"IBM\", 14)", customDataHistory, 14, IBM); // we can loop over the return values from these functions and we'll get custom data // this can be used in much the same way as the tradeBarHistory above _dailySma.Reset(); foreach (CustomData customData in customDataHistory) { _dailySma.Update(customData.EndTime, customData.Value); } // get the last year's worth of all configured custom data at the configured resolution (daily) var allCustomData = History(TimeSpan.FromDays(365)); AssertHistoryCount("History(TimeSpan.FromDays(365))", allCustomData, 250, IBM, SPY); // get the last 14 bars worth of custom data for the specified symbols at the configured resolution (daily) allCustomData = History(Securities.Keys, 14); AssertHistoryCount("History(Securities.Keys, 14)", allCustomData, 14, IBM, SPY); // NOTE: Using different resolutions require that they are properly implemented in your data type. If your // custom data source has different resolutions, it would need to be implemented in the GetSource and Reader // methods properly. //customDataHistory = History("IBM", TimeSpan.FromDays(7), Resolution.Minute); //customDataHistory = History("IBM", 14, Resolution.Minute); //allCustomData = History(TimeSpan.FromDays(365), Resolution.Minute); //allCustomData = History(Securities.Keys, 14, Resolution.Minute); //allCustomData = History(Securities.Keys, TimeSpan.FromDays(1), Resolution.Minute); //allCustomData = History(Securities.Keys, 14, Resolution.Minute); // get the last calendar year's worth of all custom data allCustomData = History(Securities.Keys, TimeSpan.FromDays(365)); AssertHistoryCount("History(Securities.Keys, TimeSpan.FromDays(365))", allCustomData, 250, IBM, SPY); // the return is a series of dictionaries containing all custom data at each time // we can loop over it to get the individual dictionaries foreach (DataDictionary customDataDictionary in allCustomData) { // we can access the dictionary to get the custom data we want var customData = customDataDictionary["IBM"]; } // we can also access the return value from the multiple symbol functions to request a single // symbol and then loop over it var singleSymbolCustomData = allCustomData.Get("IBM"); AssertHistoryCount("allCustomData.Get(\"IBM\")", singleSymbolCustomData, 250, IBM); foreach (CustomData customData in singleSymbolCustomData) { // do something with 'IBM' custom data } // we can also access individual properties on our data, this will // get the 'IBM' CustomData objects like above, but then only return the Value properties var customDataIbmValues = allCustomData.Get("IBM", "Value"); AssertHistoryCount("allCustomData.Get(\"IBM\", \"Value\")", customDataIbmValues, 250); foreach (decimal value in customDataIbmValues) { // do something with each 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 // SPY daily data arrives at 4pm, while this custom data at midnight so we get 250 * 2 points var allHistory = History(TimeSpan.FromDays(365)); AssertHistoryCount("History(TimeSpan.FromDays(365))", allHistory, 250 * 2, SPY, IBM); // 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, 390, SPY, IBM); // request the last 100 bars for the specified securities at the configured resolution allHistory = History(Securities.Keys, 100); // SPY daily data arrives at 4pm, while this custom data at midnight so we get 100 * 2 points AssertHistoryCount("History(Securities.Keys, 100)", allHistory, 100 * 2, SPY, IBM); // 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, 100, SPY, IBM); // request the last calendar years worth of history for the specified securities allHistory = History(Securities.Keys, TimeSpan.FromDays(365)); // SPY daily data arrives at 4pm, while this custom data at midnight so we get 250 * 2 points AssertHistoryCount("History(Securities.Keys, TimeSpan.FromDays(365))", allHistory, 250 * 2, SPY, IBM); // 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, 390, SPY, IBM); // 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 RegressionTestException("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 slice) { _count++; if (_count > 5 * 2) { throw new RegressionTestException($"Invalid number of bars arrived. Expected exactly 5, but received {_count}"); } 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 RegressionTestException(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(CustomData)) { 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 RegressionTestException("Unhandled case: " + typeof(T).GetBetterTypeName()); } var unexpectedSymbolsString = string.Join(" | ", unexpectedSymbols); if (!string.IsNullOrWhiteSpace(unexpectedSymbolsString)) { throw new RegressionTestException($"{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 List Languages { get; } = new() { Language.CSharp, Language.Python }; /// /// Data Points count of all timeslices of algorithm /// public long DataPoints => -1; /// /// Data Points count of the algorithm history /// public int AlgorithmHistoryDataPoints => -1; /// /// Final status of the algorithm /// public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed; /// /// 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 Orders", "1"}, {"Average Win", "0%"}, {"Average Loss", "0%"}, {"Compounding Annual Return", "1033.443%"}, {"Drawdown", "0.200%"}, {"Expectancy", "0"}, {"Start Equity", "100000"}, {"End Equity", "102696.36"}, {"Net Profit", "2.696%"}, {"Sharpe Ratio", "44.092"}, {"Sortino Ratio", "0"}, {"Probabilistic Sharpe Ratio", "0%"}, {"Loss Rate", "0%"}, {"Win Rate", "0%"}, {"Profit-Loss Ratio", "0"}, {"Alpha", "-2.58"}, {"Beta", "1.075"}, {"Annual Standard Deviation", "0.192"}, {"Annual Variance", "0.037"}, {"Information Ratio", "-95.146"}, {"Tracking Error", "0.019"}, {"Treynor Ratio", "7.862"}, {"Total Fees", "$3.49"}, {"Estimated Strategy Capacity", "$1200000000.00"}, {"Lowest Capacity Asset", "SPY R735QTJ8XC9X"}, {"Portfolio Turnover", "25.02%"}, {"Drawdown Recovery", "1"}, {"OrderListHash", "70f21e930175a2ec9d465b21edc1b6d9"} }; } }