示例#1
0
		/// <summary>
		/// Initializes the sim from the config object.
		/// </summary>
		/// <param name="config">Object with all the parameters that can be used to config how this sim runs</param>
		public bool CreateFromConfig(SimulatorConfig config, TickerDataStore dataStore)
		{
			Config = config;
			DataStore = dataStore;
			DataOutput = new DataOutputter();

			if (Config.UseTodaysDate)
			{
				Config.EndDate = DateTime.Now.Date;
			}

			// Load the config file with the instument list for all the symbols that we 
			// want to test.
			SortedDictionary<string, TickerExchangePair> fileInstruments = new SortedDictionary<string, TickerExchangePair>();
			string line;
			try
			{
				StreamReader file = new StreamReader(Config.InstrumentListFile);
				while ((line = file.ReadLine()) != null)
				{
					string[] pair = line.Split(',');
					TickerExchangePair newTicker = new TickerExchangePair(pair[1], pair[0]);
					string key = newTicker.ToString();
					if (fileInstruments.ContainsKey(key) == false)
					{
						fileInstruments[key] = newTicker;
					}
					else
					{
						WriteMessage("Duplicate ticker in file: " + newTicker.ToString());
					}
				}
			}
			catch (Exception e)
			{
				WriteMessage("Error loading instrument file!\n" + e.Message);
				return false;
			}

			WriteMessage("Initializing ticker data");
			
			// TODO: there has to be a better place for this!
			//if (Directory.Exists(Simulator.Config.OutputFolder + "\\higher"))
			//{
			//	Directory.Delete(Simulator.Config.OutputFolder + "\\higher", true);
			//}

			// Add all the symbols as dependent strategies using the bestofsubstrategies
			ConcurrentDictionary<string, BestOfRootStrategies> downloadedInstruments = new ConcurrentDictionary<string, BestOfRootStrategies>();
#if DEBUG			
			foreach (KeyValuePair<string, TickerExchangePair> item in fileInstruments)
#else
			Parallel.ForEach(fileInstruments, item =>
#endif
			{
				// Get the data for the symbol and save it for later so we can output it.
				TickerData tickerData = DataStore.GetTickerData(item.Value, config.StartDate, config.EndDate);
				if (tickerData != null)
				{
					DataOutput.SaveTickerData(tickerData);
					//RunnableFactory factory = new RunnableFactory(tickerData);

					// This strategy will find the best strategy for this instrument everyday and save the value.
					downloadedInstruments[item.Value.ToString()] = new BestOfRootStrategies(tickerData);
				}
				else
				{
					WriteMessage("No ticker data for " + item.Value.ToString());
				}
#if DEBUG
			}
#else
			});
#endif

			// Want to store the instrument data in a sorted way so that we always run things
			// in the same order.
			Instruments = new SortedDictionary<string, BestOfRootStrategies>(downloadedInstruments.ToDictionary(kvp => kvp.Key, kvp => kvp.Value));

			NumberOfBars = DataStore.SimTickerDates.Count;
			Broker = new Broker(Config.InitialAccountBalance, NumberOfBars);

			return DataStore.SimTickerDates.Count > 0;
		}
示例#2
0
        /// <summary>
        /// Gets the symbol data from either memory, disk, or a server.
        /// </summary>
        /// <param name="ticker">Ticker to get data for</param>
        /// <param name="start">Start date for the data</param>
        /// <param name="end">End date for the data</param>
        /// <returns>Data (price, volume, etc) for the ticker</returns>
        public TickerData GetTickerData(TickerExchangePair ticker, DateTime start, DateTime end)
        {
            TickerData data = new TickerData(ticker);

            // The symbol exists in memory already.
            int key = ticker.GetHashCode();

            if (_symbolsInMemory.ContainsKey(key))
            {
                TickerData inMemoryData = _symbolsInMemory[key];

                // We don't have all the data in memory past the end, so we need to get that data and append it.
                if (end > inMemoryData.End || start < inMemoryData.Start)
                {
                    data = GetDataFromDiskOrServer(ticker, start, end);

                    // Update the data in memory so it has it next time it runs.
                    _symbolsInMemory[key] = data;

                    // Return only the dates requested.
                    data = data.SubSet(start, end);
                }
                // Not requesting everything that is in the memory. This is generally the case.
                else if (start > inMemoryData.Start || end < inMemoryData.End)
                {
                    data = inMemoryData.SubSet(start, end);
                }
                // We wanted everything that is memory.
                else
                {
                    data = inMemoryData;
                }
            }
            // Symbol isn't in memory so we need to load from the disk or the server.
            else
            {
                // Always start by loading everything we have our earliest date so that
                // anytime we eventually will have all the data saved allowing us to
                // test lots of different date ranges without having to hit the disk or internet.
                data = GetDataFromDiskOrServer(ticker, start, end);

                if (data != null)
                {
                    // Save in memory for next time.
                    _symbolsInMemory[key] = data;

                    data = data.SubSet(start, end);
                }
            }

            if (data != null)
            {
                // Save all the dates that this ticker has so that we have a list of dates that we can
                // iterate through for trading periods. This is because each ticker can potentially have
                // different trading dates but for the main sim we want to go through all dates and if
                // the ticker has data for that time, we'll use it.
                lock (_dateLock)
                {
                    for (int i = 0; i < data.Dates.Count; i++)
                    {
                        if (SimTickerDates.ContainsKey(data.Dates[i]) == false)
                        {
                            SimTickerDates[data.Dates[i]] = true;
                        }
                    }
                }
            }

            return(data);
        }
示例#3
0
        /// <summary>
        /// Appends the other data to the data already in this class. It doesn't overwrite data
        /// for existing dates, so it can only prepend data to the start or append to the end.
        /// </summary>
        /// <param name="otherData">Data to append</param>
        public void AppendData(TickerData otherData)
        {
            // Prepend
            if (otherData.Start < Start)
            {
                // Find the index in the other data where this data starts.
                int copyEndIndex;
                for (copyEndIndex = 0; copyEndIndex < otherData.Dates.Count; copyEndIndex++)
                {
                    if (otherData.Dates[copyEndIndex] >= Start)
                    {
                        break;
                    }
                }

                // Insert all the new data at the front of the existing data.
                Dates.InsertRange(0, otherData.Dates.GetRange(0, copyEndIndex));
                Open.InsertRange(0, otherData.Open.GetRange(0, copyEndIndex));
                Close.InsertRange(0, otherData.Close.GetRange(0, copyEndIndex));
                High.InsertRange(0, otherData.High.GetRange(0, copyEndIndex));
                Low.InsertRange(0, otherData.Low.GetRange(0, copyEndIndex));
                Volume.InsertRange(0, otherData.Volume.GetRange(0, copyEndIndex));

                // Extras
                Typical.InsertRange(0, otherData.Typical.GetRange(0, copyEndIndex));
                Median.InsertRange(0, otherData.Median.GetRange(0, copyEndIndex));
                HigherTimeframeTrend.InsertRange(0, otherData.HigherTimeframeTrend.GetRange(0, copyEndIndex));

                for (int i = 0; i < HigherTimeframeValueStrings.Length; i++)
                {
                    string key = HigherTimeframeValueStrings[i];
                    HigherTimeframeValues[key].InsertRange(0, otherData.HigherTimeframeValues[key].GetRange(0, copyEndIndex));
                }
            }

            // Append
            if (otherData.End > End)
            {
                // Find the index where the other data passes the end of the existing data.
                int copyStartIndex;
                for (copyStartIndex = 0; copyStartIndex < otherData.Dates.Count; copyStartIndex++)
                {
                    if (otherData.Dates[copyStartIndex] > End)
                    {
                        break;
                    }
                }

                // Append the new data to the end of the existing data.
                Dates.AddRange(otherData.Dates.GetRange(copyStartIndex, otherData.Dates.Count - copyStartIndex));
                Open.AddRange(otherData.Open.GetRange(copyStartIndex, otherData.Open.Count - copyStartIndex));
                Close.AddRange(otherData.Close.GetRange(copyStartIndex, otherData.Close.Count - copyStartIndex));
                High.AddRange(otherData.High.GetRange(copyStartIndex, otherData.High.Count - copyStartIndex));
                Low.AddRange(otherData.Low.GetRange(copyStartIndex, otherData.Low.Count - copyStartIndex));
                Volume.AddRange(otherData.Volume.GetRange(copyStartIndex, otherData.Volume.Count - copyStartIndex));

                // Extras
                Typical.AddRange(otherData.Typical.GetRange(copyStartIndex, otherData.Typical.Count - copyStartIndex));
                Median.AddRange(otherData.Median.GetRange(copyStartIndex, otherData.Median.Count - copyStartIndex));
                HigherTimeframeTrend.AddRange(otherData.HigherTimeframeTrend.GetRange(copyStartIndex, otherData.HigherTimeframeTrend.Count - copyStartIndex));

                for (int i = 0; i < HigherTimeframeValueStrings.Length; i++)
                {
                    string key = HigherTimeframeValueStrings[i];
                    HigherTimeframeValues[key].AddRange(otherData.HigherTimeframeValues[key].GetRange(copyStartIndex, otherData.HigherTimeframeValues[key].Count - copyStartIndex));
                }
            }

            Start   = Dates[0];
            End     = Dates[Dates.Count - 1];
            NumBars = Dates.Count;
            SaveDates();
        }
示例#4
0
        /// <summary>
        /// Returns aggregated bars for the higher timeframe from the lower time frame data.
        /// </summary>
        /// <param name="ticker">Lower timeframe ticker data</param>
        /// <returns>Higher timeframe ticker data</returns>
        private TickerData GetHigherTimeframeBars(TickerData ticker)
        {
            double open     = 0;
            double high     = 0;
            double low      = 0;
            double close    = 0;
            long   volume   = 0;
            int    barCount = 0;

            // Reset the states since we'll calculate them again.
            TickerData higherData = new TickerData(ticker.TickerAndExchange);

            int currentWeek = UtilityMethods.GetIso8601WeekOfYear(ticker.Dates.First());

            // Aggregate all the data into the higher timeframe.
            for (int i = 0; i < ticker.Dates.Count; i++)
            {
                // The first bar open we'll treat as the open price and set the high and low.
                // Volume gets reset as it's cumulative through all the bars.
                if (barCount == 0)
                {
                    open   = ticker.Open[i];
                    low    = ticker.Low[i];
                    high   = ticker.High[i];
                    volume = 0;
                }

                // If this low is lower than the saved low, we have a new low.
                // Same for high but opposite of course.
                if (ticker.Low[i] < low)
                {
                    low = ticker.Low[i];
                }
                if (ticker.High[i] > high)
                {
                    high = ticker.High[i];
                }

                // Move to the next bar to aggregate from.
                ++barCount;
                volume += ticker.Volume[i];

                // The last bar close is treated as the close. Now it's time to save all
                // the aggregated data as one bar for the higher timeframe.
                // We also want to do this if the for loop is just about to exit. We may not
                // have the number of bars we wanted for the aggregate, but we want to at least have
                // something for the last bar. Ex. We have 5 bars set for the higher timeframe length,
                // but we've only got 3 bars of data and the for loop will end on the next iteration.
                // In that case we want to use the 3 bars we have for the data.
                if ((i + 1 == ticker.Dates.Count) ||
                    (Simulator.Config.DataType == "daily" && UtilityMethods.GetIso8601WeekOfYear(ticker.Dates[i + 1]) != currentWeek) ||
                    (Simulator.Config.DataType != "daily" && barCount == Simulator.Config.NumBarsHigherTimeframe))
                {
                    close = ticker.Close[i];

                    higherData.Dates.Add(ticker.Dates[i]);                     // Use the ending aggregated date as the date for the higher timeframe.
                    higherData.Open.Add(open);
                    higherData.High.Add(high);
                    higherData.Low.Add(low);
                    higherData.Close.Add(close);
                    higherData.Volume.Add(volume);
                    higherData.NumBars = higherData.Dates.Count;

                    // Extras
                    higherData.Typical.Add((high + low + close) / 3);
                    higherData.Median.Add((high + low) / 2);

                    // Start aggregating a new set.
                    barCount = 0;
                    int nextWeekIndex = i + 1 == ticker.Dates.Count ? i : i + 1;
                    currentWeek = UtilityMethods.GetIso8601WeekOfYear(ticker.Dates[nextWeekIndex]);
                }
            }

            return(higherData);
        }
示例#5
0
        /// <summary>
        /// Returns what type of orders are allowed for this bar based on the
        /// higher time frame momentum analysis.
        /// </summary>
        /// <param name="ticker">Ticker data</param>
        /// <param name="lastState">Last state of the higher timeframe</param>
        /// <returns>Order type allowed for the last bar of the ticker data</returns>
        private double GetHigherTimerframeExtras(TickerData ticker, double lastState)
        {
            // Get all the bars for the higher timeframe.
            TickerData higherTickerData = GetHigherTimeframeBars(ticker);

            Sma sma = new Sma(higherTickerData)
            {
                Period = 35
            };

            sma.Initialize();
            sma.RunToBar(higherTickerData.NumBars - 1);
            sma.Shutdown();
            ticker.HigherTimeframeValues["Sma"].Add(sma.Avg.Last());

            Atr atrInd = new Atr(higherTickerData)
            {
                Period = 14
            };

            atrInd.Initialize();
            atrInd.RunToBar(higherTickerData.NumBars - 1);
            atrInd.Shutdown();
            ticker.HigherTimeframeValues["Atr"].Add(atrInd.Value.Last());

            KeltnerChannel keltner = new KeltnerChannel(higherTickerData);

            keltner.Initialize();
            keltner.RunToBar(higherTickerData.NumBars - 1);
            keltner.Shutdown();
            ticker.HigherTimeframeValues["KeltnerUpper"].Add(keltner.Upper.Last());
            ticker.HigherTimeframeValues["KeltnerMidline"].Add(keltner.Midline.Last());
            ticker.HigherTimeframeValues["KeltnerLower"].Add(keltner.Lower.Last());

            DtOscillator dtosc = new DtOscillator(higherTickerData);

            dtosc.Initialize();
            dtosc.RunToBar(higherTickerData.NumBars - 1);
            dtosc.Shutdown();
            ticker.HigherTimeframeValues["DtoscSK"].Add(dtosc.SK.Last());
            ticker.HigherTimeframeValues["DtoscSD"].Add(dtosc.SK.Last());

            ticker.HigherTimeframeValues["Close"].Add(higherTickerData.Close.Last());

            // Return what kind orders are allowed.
            double state = GetHigherTimeframeStateFromIndicator(dtosc, dtosc.Data.NumBars - 1, lastState);

            ////////////////// START HIGHER TIME FRAME DEBUGGING ////////////////////
            if (Simulator.Config.OutputHigherTimeframeData)
            {
                DateTime      outputDate = higherTickerData.Dates[higherTickerData.Dates.Count - 1];
                List <double> states     = new List <double>(ticker.HigherTimeframeTrend);
                states.Add(state);
                Simulator.DataOutput.OutputHigherTimeframeData(
                    outputDate,
                    new List <Indicator>()
                {
                    dtosc, atrInd, keltner, sma
                },
                    higherTickerData,
                    ticker,
                    states);
            }
            //////////////////  END  HIGHER TIME FRAME DEBUGGING ////////////////////

            return(state);
        }
示例#6
0
        /// <summary>
        /// Creates an object of ticker data from the stream passed in.
        /// </summary>
        /// <param name="data">String of ticker data</param>
        /// <param name="ticker">Ticker name for this data string</param>
        /// <param name="isFromDisk">True if this string is loaded from our disk, saves a lot of calculation time</param>
        /// <param name="start">Start date of the data</param>
        /// <param name="end">End date of the data</param>
        /// <returns>Returns an object created from the ticker data string</returns>
        private TickerData CreateTickerDataFromString(string data, TickerExchangePair ticker, bool isFromDisk, DateTime start, DateTime end)
        {
            if (string.IsNullOrEmpty(data))
            {
                throw new Exception("No ticker data to parse.");
            }

            using (StringReader reader = new StringReader(data))
            {
                string line = string.Empty;

                // Strip off the headers if the are present
                if (reader.Peek() == 68)                 // "D"
                {
                    reader.ReadLine();
                }

                TickerData tickerData = new TickerData(ticker);

                // Value for an invalid date.
                DateTime invalidDate = new DateTime(1970, 1, 1);

                // Read each line of the string and convert it into numerical data and dates.
                do
                {
                    line = reader.ReadLine();
                    if (line != null)
                    {
                        string[] splitData     = line.Split(new char[] { ',' });
                        DateTime lineDate      = DateTime.MaxValue;
                        long     lineDateDigit = 0;
                        if (long.TryParse(splitData[0], out lineDateDigit))
                        {
                            lineDate = UtilityMethods.ConvertFromUnixTimestamp(splitData[0]);
                        }
                        else
                        {
                            lineDate = DateTime.Parse(splitData[0]);
                        }

                        // Because of the way google returns data, we don't always get our exact dates.
                        // What we get is an interval of dates containing the ones we asked for, so
                        // we'll filter that data down to just the dates we want.
                        if (start != invalidDate && lineDate < start)
                        {
                            continue;
                        }
                        if (end != invalidDate && lineDate > end)
                        {
                            break;
                        }

                        // Sometimes google has random 0's or 0.01 values for things so we'll just skip those bars.
                        if (!IsDataFieldValid(splitData, 1) ||
                            !IsDataFieldValid(splitData, 2) ||
                            !IsDataFieldValid(splitData, 3) ||
                            !IsDataFieldValid(splitData, 4) ||
                            !IsDataFieldValid(splitData, 5))
                        {
                            continue;
                        }

                        // Add the data to our object.
                        double open   = Convert.ToDouble(splitData[1]);
                        double high   = Convert.ToDouble(splitData[2]);
                        double low    = Convert.ToDouble(splitData[3]);
                        double close  = Convert.ToDouble(splitData[4]);
                        long   volume = Convert.ToInt64(splitData[5]);

                        tickerData.Dates.Add(lineDate);
                        tickerData.Open.Add(open);
                        tickerData.High.Add(high);
                        tickerData.Low.Add(low);
                        tickerData.Close.Add(close);
                        tickerData.Volume.Add(volume);
                        tickerData.NumBars = tickerData.Dates.Count;

                        // If this data is from the disk we don't need to calculate the extra fields since
                        // we've already saved them in the file.
                        if (isFromDisk)
                        {
                            tickerData.Typical.Add(Convert.ToDouble(splitData[(int)DataFields.Typical]));
                            tickerData.Median.Add(Convert.ToDouble(splitData[(int)DataFields.Median]));
                            tickerData.HigherTimeframeTrend.Add(Convert.ToDouble(splitData[(int)DataFields.HigherState]));

                            for (int i = 0; i < TickerData.HigherTimeframeValueStrings.Length; i++)
                            {
                                string        key          = TickerData.HigherTimeframeValueStrings[i];
                                List <double> higherValues = tickerData.HigherTimeframeValues[key];
                                higherValues.Add(Convert.ToDouble(splitData[(int)DataFields.HigherValuesStart + i]));
                            }
                        }
                        else
                        {
                            // Extra non-downloaded data.
                            high  = tickerData.High[tickerData.NumBars - 1];
                            low   = tickerData.Low[tickerData.NumBars - 1];
                            close = tickerData.Close[tickerData.NumBars - 1];
                            tickerData.Typical.Add((high + low + close) / 3);
                            tickerData.Median.Add((high + low) / 2);

                            // Calculate the higher momentum state for this bar. This is a pretty
                            // time consuming function since it has to loop back through all the
                            // bars before (and including) this one.
                            double lastValue = tickerData.HigherTimeframeTrend.Count > 0 ? tickerData.HigherTimeframeTrend[tickerData.HigherTimeframeTrend.Count - 1] : Order.OrderType.Long;
                            tickerData.HigherTimeframeTrend.Add(GetHigherTimerframeExtras(tickerData, lastValue));
                        }
                    }
                } while (line != null);

                tickerData.Start = tickerData.Dates[0];
                tickerData.End   = tickerData.Dates[tickerData.Dates.Count - 1];
                tickerData.SaveDates();

                return(tickerData);
            }
        }
示例#7
0
        /// <summary>
        /// Constructor for the runnable.
        /// </summary>
        public Runnable(TickerData tickerData)
        {
            _dependents = new List <Runnable>();

            Data = tickerData;
        }
示例#8
0
 /// <summary>
 /// Add this indicator to be saved for output later.
 /// </summary>
 /// <param name="tickerData">Ticker that the indicator is calculated with</param>
 public Indicator(TickerData tickerData) : base(tickerData)
 {
     // Default to about 2 years of lookback data.
     MaxSimulationBars = 500;
     MaxPlotBars       = 500;
 }