Skip to content

Commit

Permalink
Merge pull request #92 from ooples/dev
Browse files Browse the repository at this point in the history
Fixed issues with csv methods since Yahoo doesn't support them
  • Loading branch information
ooples authored Sep 28, 2024
2 parents 2a7594d + e518736 commit be3d768
Show file tree
Hide file tree
Showing 19 changed files with 393 additions and 292 deletions.
36 changes: 12 additions & 24 deletions src/Helpers/CapitalGainHelper.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,20 @@
namespace OoplesFinance.YahooFinanceAPI.Helpers;


internal class CapitalGainHelper : YahooCsvBase
namespace OoplesFinance.YahooFinanceAPI.Helpers;

internal class CapitalGainHelper : YahooJsonBase
{
/// <summary>
/// Parses the raw csv data for the Capital Gain Data
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="csvData"></param>
/// <returns>Returns a IEnumerable<CapitalGainHelper> using the given csvData</returns>
internal override IEnumerable<T> ParseYahooCsvData<T>(IEnumerable<string[]> csvData)
internal override IEnumerable<T> ParseYahooJsonData<T>(string jsonData)
{
var parsedDataList = csvData.Select(csvRow =>
{
// Perform a try parse for all columns per row
var dateSuccess = DateTime.TryParse(csvRow[0], CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate);
var capitalGainSuccess = double.TryParse(csvRow[1], NumberStyles.Number | NumberStyles.AllowDecimalPoint | NumberStyles.Float,
CultureInfo.InvariantCulture, out var parsedCapitalGain);
var capitalGain = JsonConvert.DeserializeObject<CapitalGainDataRoot>(jsonData);

// Add either the parsed value or the default if there was a parsing error
CapitalGainData capitalGainData = new()
{
Date = dateSuccess ? parsedDate : default,
CapitalGain = capitalGainSuccess ? parsedCapitalGain : default
};
if (capitalGain != null && capitalGain.Chart?.Result != null)
{
var result = capitalGain.Chart.Result.Cast<T>();

return capitalGainData;
});
return result;
}

return (IEnumerable<T>)parsedDataList;
return [];
}
}
10 changes: 5 additions & 5 deletions src/Helpers/ChartHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ internal override IEnumerable<T> ParseYahooJsonData<T>(string jsonData)
var result = new ChartInfo
{
DateList = new List<DateTime>(root != null ? root.Timestamp.Select(x => x.FromUnixTimeStamp()) : []),
CloseList = new List<double>(root != null ? root.Indicators.Quote.SelectMany(x => x.Close.Select(y => y.GetValueOrDefault())) : []),
OpenList = new List<double>(root != null ? root.Indicators.Quote.SelectMany(x => x.Open.Select(y => y.GetValueOrDefault())) : []),
HighList = new List<double>(root != null ? root.Indicators.Quote.SelectMany(x => x.High.Select(y => y.GetValueOrDefault())) : []),
VolumeList = new List<double>(root != null ? root.Indicators.Quote.SelectMany(x => x.Volume.Select(y => y.GetValueOrDefault())) : []),
LowList = new List<double>(root != null ? root.Indicators.Quote.SelectMany(x => x.Low.Select(y => y.GetValueOrDefault())) : [])
CloseList = new List<double>(root != null ? root.Indicators?.Quote.SelectMany(x => x.Close.Select(y => y.GetValueOrDefault())) ?? [] : []),
OpenList = new List<double>(root != null ? root.Indicators?.Quote.SelectMany(x => x.Open.Select(y => y.GetValueOrDefault())) ?? [] : []),
HighList = new List<double>(root != null ? root.Indicators?.Quote.SelectMany(x => x.High.Select(y => y.GetValueOrDefault())) ?? [] : []),
VolumeList = new List<double>(root != null ? root.Indicators?.Quote.SelectMany(x => x.Volume.Select(y => (double)y.GetValueOrDefault())) ?? [] : []),
LowList = new List<double>(root != null ? root.Indicators?.Quote.SelectMany(x => x.Low.Select(y => y.GetValueOrDefault())) ?? [] : [])
};

if (result.DateList.Count == 0 || result.CloseList.Count == 0 || result.OpenList.Count == 0 || result.HighList.Count == 0 ||
Expand Down
37 changes: 12 additions & 25 deletions src/Helpers/DividendHelper.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
namespace OoplesFinance.YahooFinanceAPI.Helpers;

namespace OoplesFinance.YahooFinanceAPI.Helpers;

internal class DividendHelper : YahooCsvBase
internal class DividendHelper : YahooJsonBase
{
/// <summary>
/// Parses the raw csv data for the Dividend Data
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="csvData"></param>
/// <returns>Returns a IEnumerable<DividendData> using the given csvData</returns>
internal override IEnumerable<T> ParseYahooCsvData<T>(IEnumerable<string[]> csvData)
internal override IEnumerable<T> ParseYahooJsonData<T>(string jsonData)
{
var parsedDataList = csvData.Select(csvRow =>
{
// Perform a try parse for all columns per row
var dateSuccess = DateTime.TryParse(csvRow[0], CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate);
var dividendSuccess = double.TryParse(csvRow[1], NumberStyles.AllowDecimalPoint | NumberStyles.Float | NumberStyles.Number,
CultureInfo.InvariantCulture, out var parsedDividend);
var dividendData = JsonConvert.DeserializeObject<DividendRoot>(jsonData);

// Add either the parsed value or the default if there was a parsing error
DividendData dividendData = new()
{
Date = dateSuccess ? parsedDate : default,
Dividend = dividendSuccess ? parsedDividend : default
};
if (dividendData != null && dividendData.Chart?.Result != null)
{
var results = dividendData.Chart.Result.Cast<T>();

return dividendData;
});
return results;
}

return (IEnumerable<T>)parsedDataList;
return [];
}
}
}
11 changes: 2 additions & 9 deletions src/Helpers/DownloadHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ internal static class DownloadHelper
/// <param name="includeAdjustedClose"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
internal static async Task<IEnumerable<string[]>> DownloadRawCsvDataAsync(string symbol, DataType dataType, DataFrequency dataFrequency,
internal static async Task<string> DownloadRawCsvDataAsync(string symbol, DataType dataType, DataFrequency dataFrequency,
DateTime startDate, DateTime? endDate, bool includeAdjustedClose)
{
if (string.IsNullOrWhiteSpace(symbol))
Expand All @@ -22,15 +22,8 @@ internal static async Task<IEnumerable<string[]>> DownloadRawCsvDataAsync(string
}
else
{
var rawData = await DownloadRawDataAsync(BuildYahooCsvUrl(symbol, dataType, dataFrequency, startDate, endDate, includeAdjustedClose));

if (!string.IsNullOrWhiteSpace(rawData))
{
return GetBaseCsvData(rawData);
}
return await DownloadRawDataAsync(BuildYahooCsvUrl(symbol, dataType, dataFrequency, startDate, endDate, includeAdjustedClose));
}

return [];
}

/// <summary>
Expand Down
50 changes: 14 additions & 36 deletions src/Helpers/HistoricalHelper.cs
Original file line number Diff line number Diff line change
@@ -1,47 +1,25 @@
namespace OoplesFinance.YahooFinanceAPI.Helpers;

namespace OoplesFinance.YahooFinanceAPI.Helpers;

internal class HistoricalHelper : YahooCsvBase
internal class HistoricalHelper : YahooJsonBase
{
/// <summary>
/// Parses the raw csv data for the Historical Data
/// Parses the raw json data for the Financial Data
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="csvData"></param>
/// <returns>Returns a IEnumerable<HistoricalData> using the given csvData</returns>
internal override IEnumerable<T> ParseYahooCsvData<T>(IEnumerable<string[]> csvData)
/// <param name="jsonData"></param>
/// <returns></returns>
internal override IEnumerable<T> ParseYahooJsonData<T>(string jsonData)
{
var parsedDataList = csvData.Select(csvRow =>
{
// Perform a try parse for all columns per row
var dateSuccess = DateTime.TryParse(csvRow[0], CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate);
var openSuccess = double.TryParse(csvRow[1], NumberStyles.AllowDecimalPoint | NumberStyles.Float | NumberStyles.Number,
CultureInfo.InvariantCulture, out var parsedOpen);
var highSuccess = double.TryParse(csvRow[2], NumberStyles.AllowDecimalPoint | NumberStyles.Float | NumberStyles.Number,
CultureInfo.InvariantCulture, out var parsedHigh);
var lowSuccess = double.TryParse(csvRow[3], NumberStyles.AllowDecimalPoint | NumberStyles.Float | NumberStyles.Number,
CultureInfo.InvariantCulture, out var parsedLow);
var closeSuccess = double.TryParse(csvRow[4], NumberStyles.AllowDecimalPoint | NumberStyles.Float | NumberStyles.Number,
CultureInfo.InvariantCulture, out var parsedClose);
var adjCloseSuccess = double.TryParse(csvRow[5], NumberStyles.AllowDecimalPoint | NumberStyles.Float | NumberStyles.Number,
CultureInfo.InvariantCulture, out var parsedAdjClose);
var volumeSuccess = double.TryParse(csvRow[6], NumberStyles.Integer | NumberStyles.Number,
CultureInfo.InvariantCulture, out var parsedVolume);
var historicalData = JsonConvert.DeserializeObject<HistoricalDataRoot>(jsonData);

// Add either the parsed value or the default if there was a parsing error
HistoricalData historicalData = new()
{
Date = dateSuccess ? parsedDate : default,
Open = openSuccess ? parsedOpen : default,
High = highSuccess ? parsedHigh : default,
Low = lowSuccess ? parsedLow : default,
Close = closeSuccess ? parsedClose : default,
AdjClose = adjCloseSuccess ? parsedAdjClose : default,
Volume = volumeSuccess ? parsedVolume : default
};
if (historicalData != null && historicalData.Chart?.Result != null)
{
var result = historicalData.Chart.Result.Cast<T>();

return historicalData;
});
return result;
}

return (IEnumerable<T>)parsedDataList;
return [];
}
}
33 changes: 11 additions & 22 deletions src/Helpers/StockSplitHelper.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,19 @@
namespace OoplesFinance.YahooFinanceAPI.Helpers;

namespace OoplesFinance.YahooFinanceAPI.Helpers;

internal class StockSplitHelper : YahooCsvBase
internal class StockSplitHelper : YahooJsonBase
{
/// <summary>
/// Parses the raw csv data for the Stock Split Data
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="csvData"></param>
/// <returns>Returns a IEnumerable<StockSplitData> using the given csvData</returns>
internal override IEnumerable<T> ParseYahooCsvData<T>(IEnumerable<string[]> csvData)
internal override IEnumerable<T> ParseYahooJsonData<T>(string jsonData)
{
var parsedDataList = csvData.Select(csvRow =>
{
// Perform a try parse for all columns per row
var dateSuccess = DateTime.TryParse(csvRow[0], CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate);
var stockSplitData = JsonConvert.DeserializeObject<StockSplitRoot>(jsonData);

// Add either the parsed value or the default if there was a parsing error
StockSplitData stockSplitData = new()
{
Date = dateSuccess ? parsedDate : default,
StockSplit = csvRow.Length > 1 ? csvRow[1] : string.Empty
};
if (stockSplitData != null && stockSplitData.Chart?.Result != null)
{
var results = stockSplitData.Chart.Result.Cast<T>();

return stockSplitData;
});
return results;
}

return (IEnumerable<T>)parsedDataList;
return [];
}
}
2 changes: 1 addition & 1 deletion src/Helpers/UrlHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal static class UrlHelper
/// <param name="includeAdjClose"></param>
/// <returns></returns>
internal static string BuildYahooCsvUrl(string symbol, DataType dataType, DataFrequency dataFrequency, DateTime startDate, DateTime? endDate, bool includeAdjClose) =>
string.Format(CultureInfo.InvariantCulture, $"https://query2.finance.yahoo.com/v7/finance/download/{symbol}?period1={startDate.ToUnixTimestamp()}" +
string.Format(CultureInfo.InvariantCulture, $"https://query2.finance.yahoo.com/v8/finance/chart/{symbol}?period1={startDate.ToUnixTimestamp()}" +
$"&period2={(endDate ?? DateTime.Now).ToUnixTimestamp()}&interval={GetFrequencyString(dataFrequency)}&events={GetEventsString(dataType)}" +
$"&includeAdjustedClose={includeAdjClose}");

Expand Down
9 changes: 4 additions & 5 deletions src/Models/CapitalGainData.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
namespace OoplesFinance.YahooFinanceAPI.Models;

[Serializable]
public class CapitalGainData
public class CapitalGainDataRoot
{
public DateTime Date { get; set; }

public double CapitalGain { get; set; }
}
[JsonProperty("chart")]
public Chart? Chart { get; set; }
}
103 changes: 2 additions & 101 deletions src/Models/ChartData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,87 +9,6 @@ public class ChartData
public object Error { get; set; } = new();
}

public class CurrentTradingPeriod
{
[JsonProperty("pre")]
public TradingPeriod Pre { get; set; } = new();

[JsonProperty("regular")]
public TradingPeriod Regular { get; set; } = new();

[JsonProperty("post")]
public TradingPeriod Post { get; set; } = new();
}

public class Indicators
{
[JsonProperty("quote")]
public List<ChartQuote> Quote { get; set; } = [];
}

public class Meta
{
[JsonProperty("currency")]
public string Currency { get; set; } = string.Empty;

[JsonProperty("symbol")]
public string Symbol { get; set; } = string.Empty;

[JsonProperty("exchangeName")]
public string ExchangeName { get; set; } = string.Empty;

[JsonProperty("instrumentType")]
public string InstrumentType { get; set; } = string.Empty;

[JsonProperty("firstTradeDate")]
public int? FirstTradeDate { get; set; }

[JsonProperty("regularMarketTime")]
public int? RegularMarketTime { get; set; }

[JsonProperty("hasPrePostMarketData")]
public bool? HasPrePostMarketData { get; set; }

[JsonProperty("gmtoffset")]
public int? Gmtoffset { get; set; }

[JsonProperty("timezone")]
public string Timezone { get; set; } = string.Empty;

[JsonProperty("exchangeTimezoneName")]
public string ExchangeTimezoneName { get; set; } = string.Empty;

[JsonProperty("regularMarketPrice")]
public double? RegularMarketPrice { get; set; }

[JsonProperty("chartPreviousClose")]
public double? ChartPreviousClose { get; set; }

[JsonProperty("previousClose")]
public double? PreviousClose { get; set; }

[JsonProperty("scale")]
public int? Scale { get; set; }

[JsonProperty("priceHint")]
public int? PriceHint { get; set; }

[JsonProperty("currentTradingPeriod")]
public CurrentTradingPeriod CurrentTradingPeriod { get; set; } = new();

[JsonProperty("tradingPeriods")]
public List<List<TradingPeriod>> TradingPeriods { get; set; } = [];

[JsonProperty("dataGranularity")]
public string DataGranularity { get; set; } = string.Empty;

[JsonProperty("range")]
public string Range { get; set; } = string.Empty;

[JsonProperty("validRanges")]
public List<string> ValidRanges { get; set; } = [];
}

public class TradingPeriod
{
[JsonProperty("timezone")]
Expand All @@ -105,34 +24,16 @@ public class TradingPeriod
public int? Gmtoffset { get; set; }
}

public class ChartQuote
{
[JsonProperty("open")]
public List<double?> Open { get; set; } = [];

[JsonProperty("low")]
public List<double?> Low { get; set; } = [];

[JsonProperty("volume")]
public List<double?> Volume { get; set; } = [];

[JsonProperty("close")]
public List<double?> Close { get; set; } = [];

[JsonProperty("high")]
public List<double?> High { get; set; } = [];
}

public class ChartResult
{
[JsonProperty("meta")]
public Meta Meta { get; set; } = new();
public Meta? Meta { get; set; }

[JsonProperty("timestamp")]
public List<long> Timestamp { get; set; } = [];

[JsonProperty("indicators")]
public Indicators Indicators { get; set; } = new();
public Indicators? Indicators { get; set; }
}

public class ChartRoot
Expand Down
Loading

0 comments on commit be3d768

Please sign in to comment.