public void Process(Price[] shareData, SimpleSearchSettings settings) { this.Results = new List<List<Result>>(); int count = shareData.Count(); Price? lastSellPoint = null; List<Result> currentRun = new List<Result>(); int buyPointIndex = 0; decimal? phase2Slope = null, phase2Intercept = null; while (buyPointIndex < count) { if (currentRun.Count < settings.numerOfRepeats) { var buyPoint = shareData[buyPointIndex]; var sellPoint = buyPoint; bool found = false; for (int sellPointIndex = buyPointIndex + 1; sellPointIndex < count && (sellPoint.date - buyPoint.date).TotalDays < settings.riseSearchPeriodInDays; sellPointIndex++) { sellPoint = shareData[sellPointIndex]; if (((sellPoint.closePrice - buyPoint.closePrice) * 100 / buyPoint.closePrice) > settings.requiredChangeRate) { currentRun.Add(new Result() { buy = buyPoint, sell = sellPoint, state = ResultState.OK }); lastSellPoint = sellPoint; buyPointIndex = sellPointIndex + 1; phase2Slope = phase2Intercept = null; found = true; break; } } bool withinFallBuyPeriod = lastSellPoint == null || (buyPoint.date - lastSellPoint.Value.date).TotalDays < settings.fallSearchPeriodInDays; if (!found && !withinFallBuyPeriod) { currentRun.Clear(); lastSellPoint = null; } } else { bool foundBuyPoint = false, foundSellPoint = false; do { double[] x = currentRun.Select(c => (double)c.buy.date.Ticks).ToArray(); double[] y = currentRun.Select(c => (double)c.buy.closePrice).ToArray(); double slope, intercept; MathExtension.GenerateLinearBestFit(x, y, out slope, out intercept); phase2Slope = (decimal)slope; phase2Intercept = (decimal)intercept; foundBuyPoint = foundSellPoint = false; Price buyPoint, sellPoint; do { buyPoint = shareData[buyPointIndex++]; foundBuyPoint = (buyPoint.closePrice <= (phase2Slope * buyPoint.date.Ticks + phase2Intercept)); } while (buyPointIndex < count-1 && !foundBuyPoint && (buyPoint.date - lastSellPoint.Value.date).TotalDays < settings.fallSearchPeriodInDays); sellPoint = buyPoint; if (foundBuyPoint) { for (int sellPointIndex = buyPointIndex; sellPointIndex < count && !foundSellPoint && (sellPoint.date - buyPoint.date).TotalDays < settings.riseSearchPeriodInDays; sellPointIndex++) { sellPoint = shareData[sellPointIndex]; if (((sellPoint.closePrice - buyPoint.closePrice) * 100 / buyPoint.closePrice) > settings.requiredChangeRate) { foundSellPoint = true; buyPointIndex = sellPointIndex; break; } } currentRun.Add(new Result() { buy = buyPoint, sell = sellPoint, state = foundSellPoint ? ResultState.OK : ResultState.FailedFindingSellPoint }); } } while (foundSellPoint); if (currentRun.Count >= settings.numerOfRepeats) Results.Add(currentRun); currentRun = new List<Result>(); } buyPointIndex++; } }
public static IEnumerable<Price> Get(string symbol) { List<Price> result = new List<Price>(); DateTime now = DateTime.Now; string url = string.Format("http://real-chart.finance.yahoo.com/table.csv?s={0}&d={2}&e={1}&f={3}&g=d&a=1&b=1&c=1900&ignore=.csv", symbol, now.Day, now.Month - 1, now.Year); string file = string.Empty; using (WebClient webClient = new WebClient()) { file = webClient.DownloadString(url); } var rows = file.Split('\n'); if (rows.Length == 0) return new Price[0]; var fields = rows[0].Split(','); if (fields.Length != 7) throw new ApplicationException(string.Format("CSV file (for symbol {0}) download from Yahoo does not have the correct number of columns currently has {1} expected 7", symbol, fields.Length)); if (fields[0] != "Date") throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 0 column name has {1} expected Date", symbol, fields[0])); if (fields[1] != "Open") throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 1 column name has {1} expected Open", symbol, fields[0])); if (fields[2] != "High") throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 2 column name has {1} expected High", symbol, fields[0])); if (fields[3] != "Low") throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 3 column name has {1} expected Low", symbol, fields[0])); if (fields[4] != "Close") throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 4 column name has {1} expected Close", symbol, fields[0])); if (fields[5] != "Volume") throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 5 column name has {1} expected Volume", symbol, fields[0])); if (!fields[6].StartsWith("Adj Close")) throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 6 column name has {1} expected Adj Close", symbol, fields[0])); foreach (var row in rows.Skip(1)) { try { fields = row.Split(','); var price = new Price() { date = DateTime.ParseExact(fields[0], "yyyy-MM-dd", CultureInfo.CurrentCulture), openPrice = decimal.Parse(fields[1]), highPrice = decimal.Parse(fields[2]), lowPrice = decimal.Parse(fields[3]), closePrice = decimal.Parse(fields[4]), //volume = long.Parse(fields[5]), //adjClose = decimal.Parse(fields[6]) }; result.Add(price); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("HistoricalPricwReader.Get failed reading line {0} error is {1}", row, ex.Message); } } result.Reverse(); return result; }
public static IEnumerable <Price> Get(string symbol) { List <Price> result = new List <Price>(); DateTime now = DateTime.Now; string url = string.Format("http://real-chart.finance.yahoo.com/table.csv?s={0}&d={2}&e={1}&f={3}&g=d&a=1&b=1&c=1900&ignore=.csv", symbol, now.Day, now.Month - 1, now.Year); string file = string.Empty; using (WebClient webClient = new WebClient()) { file = webClient.DownloadString(url); } var rows = file.Split('\n'); if (rows.Length == 0) { return(new Price[0]); } var fields = rows[0].Split(','); if (fields.Length != 7) { throw new ApplicationException(string.Format("CSV file (for symbol {0}) download from Yahoo does not have the correct number of columns currently has {1} expected 7", symbol, fields.Length)); } if (fields[0] != "Date") { throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 0 column name has {1} expected Date", symbol, fields[0])); } if (fields[1] != "Open") { throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 1 column name has {1} expected Open", symbol, fields[0])); } if (fields[2] != "High") { throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 2 column name has {1} expected High", symbol, fields[0])); } if (fields[3] != "Low") { throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 3 column name has {1} expected Low", symbol, fields[0])); } if (fields[4] != "Close") { throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 4 column name has {1} expected Close", symbol, fields[0])); } if (fields[5] != "Volume") { throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 5 column name has {1} expected Volume", symbol, fields[0])); } if (!fields[6].StartsWith("Adj Close")) { throw new ApplicationException(string.Format("CSV file (for symbol {0}) has invalid 6 column name has {1} expected Adj Close", symbol, fields[0])); } foreach (var row in rows.Skip(1)) { try { fields = row.Split(','); var price = new Price() { date = DateTime.ParseExact(fields[0], "yyyy-MM-dd", CultureInfo.CurrentCulture), openPrice = decimal.Parse(fields[1]), highPrice = decimal.Parse(fields[2]), lowPrice = decimal.Parse(fields[3]), closePrice = decimal.Parse(fields[4]), //volume = long.Parse(fields[5]), //adjClose = decimal.Parse(fields[6]) }; result.Add(price); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("HistoricalPricwReader.Get failed reading line {0} error is {1}", row, ex.Message); } } result.Reverse(); return(result); }