Last active
January 4, 2018 01:54
-
-
Save PJensen/7a3f147f7fc1005598e099ea6f1b9059 to your computer and use it in GitHub Desktop.
Downloads CAPS ratings from the Motley Fool API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Data; | |
using System.Diagnostics; | |
using System.IO; | |
using System.Linq; | |
using System.Net; | |
using System.Reflection; | |
using System.Text; | |
using System.Xml.Serialization; | |
namespace ConsoleApplication1 | |
{ | |
public class EntryPoint | |
{ | |
/// <summary> | |
/// The entrypoint for the program | |
/// </summary> | |
static void Main() | |
{ | |
#region test XML serialization / deserialization | |
string xmlTestMessage; | |
if (!TestXML(out xmlTestMessage)) | |
{ | |
WriteErrorMessage(xmlTestMessage); | |
PressAnyKey(); | |
} | |
#endregion | |
// create a ratings client with our API key | |
// TODO: paste your api key here | |
var ratingClient = new MotleyFoolCapsRatingClient("3d01a88a-d660-421b-8abb-c911cb6a3c59"); | |
// create an empty list of ratings that will be built up in subsequent calls. | |
var allRatings = new List<MotleyFoolCapsRatingClient.Ticker>(); | |
// create a new data-table for storing the ratings data | |
var tmpDataTable = new System.Data.DataTable(); | |
// add the columns that we want to store in the extract. | |
tmpDataTable.Columns.Add("LastPriceDate"); | |
tmpDataTable.Columns.Add("CompanyName"); | |
tmpDataTable.Columns.Add("Symbol"); | |
tmpDataTable.Columns.Add("Rating"); | |
tmpDataTable.Columns.Add("AsOfDate"); | |
// fetch all of the ratings one after another and add them to the "allRatings" collection | |
foreach (var rating in MotleyFoolCapsRatingClient.AllRatings) | |
{ | |
var tickerList = ratingClient.Download(rating); | |
Console.WriteLine("Limit: {0}", tickerList.Limit); | |
Console.WriteLine("Timestamp: " + tickerList.TimeStamp); | |
// add the newly downloaded ratings to the data table | |
foreach (var detail in tickerList) | |
{ | |
tmpDataTable.Rows.Add( | |
detail.LastPriceDate, | |
detail.CompanyName, | |
detail.Symbol, | |
(int)rating, | |
DateTime.Today.ToShortDateString()); | |
} | |
} | |
// write the file to output.csv | |
File.WriteAllText("output.csv", ToCSV(tmpDataTable)); | |
// TODO: SaveAsFile "Output.CSV" using the DataTable | |
// See: http://stackoverflow.com/questions/888181/convert-datatable-to-csv-stream | |
PressAnyKey(); | |
} | |
/// <summary> | |
/// <seealso cref="http://stackoverflow.com/questions/888181/convert-datatable-to-csv-stream"/> | |
/// </summary> | |
/// <param name="table"></param> | |
/// <returns></returns> | |
public static string ToCSV(DataTable table) | |
{ | |
var result = new StringBuilder(); | |
for (int i = 0; i < table.Columns.Count; i++) | |
{ | |
result.Append(table.Columns[i].ColumnName); | |
result.Append(i == table.Columns.Count - 1 ? "\n" : ","); | |
} | |
foreach (DataRow row in table.Rows) | |
{ | |
for (int i = 0; i < table.Columns.Count; i++) | |
{ | |
result.Append(row[i].ToString()); | |
result.Append(i == table.Columns.Count - 1 ? "\n" : ","); | |
} | |
} | |
return result.ToString(); | |
} | |
/// <summary> | |
/// The Motlet Fool Caps rating client. | |
/// <seealso cref="http://developer.fool.com/docs/stars-caps-star-rating"/> | |
/// <remarks> | |
/// Downloads ratings data from the motley fool and returns deserialized objects | |
/// for later use and / or querying. | |
/// </remarks> | |
/// <example> | |
/// The following example shows how to download 5 star ratings. | |
/// <code> | |
/// var ratingClient = new MotleyFoolCapsRatingClient("API KEY"); | |
/// var fiveStarRatings = ratingClient.Download(MotleyFoolCapsRatingClient.StarRating.Five) | |
/// </code> | |
/// </example> | |
/// </summary> | |
public class MotleyFoolCapsRatingClient | |
{ | |
#region backing store | |
/// <summary> | |
/// the API key for *this* Caps rating client | |
/// </summary> | |
private readonly string _apiKey; | |
/// <summary> | |
/// the web client actually performs the request and downloads the raw data | |
/// </summary> | |
private readonly WebClient _webClient = new WebClient(); | |
#endregion | |
/// <summary> | |
/// The API URL for motley fool caps star rating | |
/// </summary> | |
private const string ApiUrlFormat = "http://www.fool.com/a/caps/ws/Ticker/Stars/{0}/?apikey={1}"; | |
/// <summary> | |
/// Creates a new motley fool caps rating client with the specified API key. | |
/// </summary> | |
/// <param name="apiKey">The api key</param> | |
public MotleyFoolCapsRatingClient(string apiKey) | |
{ | |
_apiKey = apiKey; | |
} | |
/// <summary> | |
/// All of the ratings for the motley fool client | |
/// </summary> | |
public static IEnumerable<StarRating> AllRatings | |
{ | |
get | |
{ | |
return new[] { StarRating.Five, | |
// when in "Release" mode, download everything | |
StarRating.Four, StarRating.Three, StarRating.Two, StarRating.One | |
}; | |
} | |
} | |
/// <summary> | |
/// Downloads the ticker list from motley fool | |
/// </summary> | |
/// <param name="rating"></param> | |
/// <returns></returns> | |
public TickerList Download(StarRating rating) | |
{ | |
var url = string.Format(ApiUrlFormat, (int)rating, _apiKey); | |
Console.Write("Downloading data: {0} ", url); | |
var rawData = _webClient.DownloadString(url); | |
Console.WriteLine("[Complete]"); | |
return Deserialize(rawData); | |
} | |
/// <summary> | |
/// Given a <seealso cref="TickerList"/> object return an XML string representing the object(s). | |
/// </summary> | |
/// <param name="tickerList">The ticker list to convert into a string</param> | |
/// <returns>A string representing the ticker list</returns> | |
public static string Serialize(TickerList tickerList) | |
{ | |
var serializer = new XmlSerializer(typeof(TickerList)); | |
using (var stringWriter = new System.IO.StringWriter()) | |
using (var writer = System.Xml.XmlWriter.Create(stringWriter, new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true })) | |
{ | |
serializer.Serialize(writer, tickerList); | |
return stringWriter.ToString(); | |
} | |
} | |
/// <summary> | |
/// Given an array of bytes (string) return a ticker list object. | |
/// </summary> | |
/// <param name="rawData">The array of bytes</param> | |
/// <returns>The ticker list object represented by the passed xml bytes</returns> | |
public static TickerList Deserialize(string rawData) | |
{ | |
if (string.IsNullOrEmpty(rawData)) | |
{ | |
throw new ArgumentNullException("rawData"); | |
} | |
var bytes = Encoding.UTF8.GetBytes(rawData); | |
try | |
{ | |
using (System.IO.Stream memoryStream = new System.IO.MemoryStream(bytes)) | |
{ | |
return new XmlSerializer(typeof(TickerList)).Deserialize(memoryStream) as TickerList; | |
} | |
} | |
catch | |
{ | |
return default(TickerList); | |
} | |
} | |
/// <summary> | |
/// The various star ratings from motley fool | |
/// </summary> | |
public enum StarRating | |
{ | |
[XmlEnum("1 Star Stocks")] | |
One = 1, | |
[XmlEnum("2 Star Stocks")] | |
Two = 2, | |
[XmlEnum("3 Star Stocks")] | |
Three = 3, | |
[XmlEnum("4 Star Stocks")] | |
Four = 4, | |
[XmlEnum("5 Star Stocks")] | |
Five = 5, | |
} | |
/// <summary> | |
/// The <seealso cref="TickerList"/> object from motley fool | |
/// <seealso cref="http://developer.fool.com/docs/stars-caps-star-rating"/> | |
/// </summary> | |
[Serializable, XmlRoot("TickerList")] | |
public class TickerList : List<Ticker> | |
{ | |
[XmlAttribute] | |
public string TimeStamp { get; set; } | |
[XmlAttribute] | |
public StarRating Type { get; set; } | |
[XmlAttribute] | |
public int Limit { get; set; } | |
} | |
/// <summary> | |
/// The <see cref="Ticker"/> object from motley fool. | |
/// <seealso cref="http://developer.fool.com/docs/stars-caps-star-rating"/> | |
/// </summary> | |
[Serializable] | |
public class Ticker | |
{ | |
[XmlAttribute] | |
public string Symbol { get; set; } | |
[XmlAttribute] | |
public string Exchange { get; set; } | |
[XmlAttribute] | |
public string CompanyName { get; set; } | |
[XmlAttribute] | |
public int Percentile { get; set; } | |
[XmlAttribute] | |
public decimal Day30Return { get; set; } | |
[XmlAttribute] | |
public string LastPriceDate { get; set; } | |
[XmlAttribute] | |
public int AllCompletedPicks { get; set; } | |
[XmlAttribute] | |
public int AllActivePicks { get; set; } | |
[XmlAttribute] | |
public int AllOutPicks { get; set; } | |
[XmlAttribute] | |
public int AllUnderPicks { get; set; } | |
[XmlAttribute] | |
public int ASActivePicks { get; set; } | |
[XmlAttribute] | |
public int ASOutPicks { get; set; } | |
[XmlAttribute] | |
public int ASUnderPicks { get; set; } | |
[XmlAttribute] | |
public int VPActivePicks { get; set; } | |
[XmlAttribute] | |
public int VPOutPicks { get; set; } | |
[XmlAttribute] | |
public int VPUnderPicks { get; set; } | |
[XmlAttribute] | |
public int PitchCount { get; set; } | |
} | |
} | |
/// <summary> | |
/// Writes an error message to the console window (in red) | |
/// </summary> | |
/// <param name="message">the message</param> | |
private static void WriteErrorMessage(string message) | |
{ | |
Console.ForegroundColor = ConsoleColor.Red; | |
Console.WriteLine(message); | |
Console.ForegroundColor = ConsoleColor.Gray; | |
} | |
/// <summary> | |
/// Writes "Press any key to continue ..." and awaits keypress | |
/// </summary> | |
private static void PressAnyKey() | |
{ | |
Console.WriteLine("Press any key to continue ..."); | |
Console.ReadKey(); | |
} | |
/// <summary> | |
/// Calling this method just tests serialization / deserialzation. | |
/// <remarks>Our goal here is just to establish that we can | |
/// go from raw xml to a C# object and then back.</remarks> | |
/// </summary> | |
private static bool TestXML(out string message) | |
{ | |
message = "OK"; | |
try | |
{ | |
// well create an object that we'll use for this test | |
var tickerList = new MotleyFoolCapsRatingClient.TickerList() | |
{ | |
new MotleyFoolCapsRatingClient.Ticker | |
{ | |
CompanyName = "Apple Computer", | |
Day30Return = 120.44M, | |
Exchange = "NYSE", | |
LastPriceDate = "12/12/2012", | |
Percentile = 5, | |
Symbol = "AAPL" | |
} | |
}; | |
// convert the object above into xml | |
var xml = MotleyFoolCapsRatingClient.Serialize(tickerList); | |
// convert the xml back into an object | |
var tmp = MotleyFoolCapsRatingClient.Deserialize(xml); | |
// do a few checks to ensure the same object made it back and forth | |
Debug.Assert(tmp.Count == 1); | |
// ensure everything is ther same | |
Debug.Assert(tmp[0].CompanyName == tickerList[0].CompanyName); | |
Debug.Assert(tmp[0].Day30Return == tickerList[0].Day30Return); | |
Console.WriteLine(xml); | |
// transitivity | |
// A -> B, B -> C therefore A -> C | |
return true; | |
} | |
catch (Exception ex) | |
{ | |
message = ex.Message; | |
return false; | |
} | |
} | |
} | |
} |
- Add additional columns to DataTable for the extract
- Perform the extract of the DataTable to a .CSV file
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Minor adjustment.