Skip to content

Commit

Permalink
feat(crypto): add ftx support
Browse files Browse the repository at this point in the history
  • Loading branch information
rodionlim committed Aug 18, 2021
1 parent 259b116 commit c4651c9
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 17 deletions.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Excel Stock Price Extraction
# Excel Stock/Crypto Price Extraction

This repository provides an excel addin with user defined functions to scrape stock market data from Yahoo and Google Finance.
This repository provides an excel addin with user defined functions to scrape stock market data from Yahoo and Google Finance, and Crypto data from FTX.

We only support current price for Google Finance data source while the full list of fields supported for Yahoo Finance can be found below.
We only support current price [CURRENT PRICE] for Google Finance and FTX data source while the full list of fields supported for Yahoo Finance can be found below.

![](excel-stock-webscrape-demo.gif)

Expand Down Expand Up @@ -55,6 +55,10 @@ Yahoo Finance Data Source
Google Finance Data Source
=bdp("goog",,"google") - Google's current price
=bdp("aapl",,"google") - Apple's current price
FTX Data Source
=bdp("btc/usd",,"ftx") - BTC/USD's current price
=bdp("btc-0924",,"ftx") - BTC/USD's September futures price
```

List of available fields
Expand Down
37 changes: 37 additions & 0 deletions StockScraper/StockScraper/MarketData/MdFtx.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net;
using System.Net.Http;

using Newtonsoft.Json;

namespace StockScraper
{
class MdFtx
{
private static readonly HttpClient _client = new HttpClient();
public static async Task<Dictionary<string, string>> GetQuoteSummary(string ticker)
{
// ftx ticker: btc-0924, btc/usd
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
HttpResponseMessage response = await _client.GetAsync($"https://ftx.com/api/markets/{ticker}");

// Read the content.
string responseFromServer = await response.Content.ReadAsStringAsync();

// Augment the content.
dynamic obj = JsonConvert.DeserializeObject(responseFromServer);
Dictionary<string, string> quoteSummary;
if (obj.success == true)
{
var result = obj.result;
quoteSummary = result.ToObject<Dictionary<string, string>>();
quoteSummary.Add("CURRENT PRICE", quoteSummary["price"]);
}
else
throw new ArgumentException(obj["error"]);
return quoteSummary;
}
}
}
39 changes: 25 additions & 14 deletions StockScraper/StockScraper/Scraper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using AngleSharp.Io;
using ExcelDna.Integration;
using ExcelDna.Registration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
Expand All @@ -10,7 +11,7 @@ namespace StockScraper
{
public class Scraper
{
private static readonly List<string> AvailableFields = new List<string>()
private static readonly List<string> AVAILABLE_FIELDS = new List<string>()
{
"PREVIOUS CLOSE",
"CURRENT PRICE",
Expand All @@ -37,30 +38,41 @@ public class Scraper
"1Y TARGET EST"
};

[ExcelAsyncFunction(Description = "Grab latest Yahoo/Google finance market data of a single exchange traded ticker, such as the closing price, dividend yield etc., defaults to Yahoo finance.")]
[ExcelAsyncFunction(Description = "Grab latest Yahoo/Google finance or FTX market data of a single exchange traded ticker, such as the closing price, dividend yield etc., defaults to Yahoo finance and Current Price.")]
public static async Task<object> bdp(
[ExcelArgument(Name = "ticker", Description = "Yahoo/Google finance ticker. Example: \"es3.si\", \"goog\"")] string ticker,
[ExcelArgument(Name = "ticker", Description = "Yahoo/Google finance or FTX ticker. Example: \"es3.si\", \"goog\", \"btc/usd\", \"btc-0924\"")] string ticker,
[ExcelArgument(AllowReference = true, Name = "[field]", Description = "[Optional] Yahoo finance or Google fields. Example: \"previous close\", \"market cap\", \"yield\"")] string field,
[ExcelArgument(AllowReference = true, Name = "[source]", Description = "[Optional] Specify the Data Source, defaults to yahoo. Example: \"yahoo\", \"google\"")] string source
[ExcelArgument(AllowReference = true, Name = "[source]", Description = "[Optional] Specify the Data Source, defaults to yahoo. Example: \"yahoo\", \"google\", \"ftx\"")] string source

)
{
var defaultField = "CURRENT PRICE";

field = field.ToUpper();
if (field.Length == 0) field = defaultField;
if (!AvailableFields.Contains(field)) return "#Invalid field"; // Validate user input
if (!AVAILABLE_FIELDS.Contains(field)) return "#Invalid field"; // Validate user input

if (source.Length==0) source = "yahoo";
if (!(source == "yahoo" | source == "google")) return "#Invalid data source"; // Validate user input
if (!(source == "yahoo" | source == "google" | source =="ftx")) return "#Invalid data source"; // Validate user input

if (source == "google" & field != defaultField) return "#Google finance currently only supports current price"; // Validate user input
if ((source == "google" | source == "ftx") & field != defaultField) return "#Google finance and FTX data sources currently only supports current price"; // Validate user input

Dictionary<string, string> quoteSummary;
if (source == "yahoo")
quoteSummary = await GetHTML(ticker);
else
quoteSummary = await GetHTMLGoogle(ticker);
switch (source)
{
case "yahoo":
quoteSummary = await GetHTML(ticker);
break;
case "google":
quoteSummary = await GetHTMLGoogle(ticker);
break;
case "ftx":
try { quoteSummary = await MdFtx.GetQuoteSummary(ticker);}
catch (ArgumentException e) { return e.Message; }
break;
default:
return "#Invalid data source";
}

if (double.TryParse(quoteSummary[field], out double res))
{
Expand All @@ -76,10 +88,9 @@ private static async Task<Dictionary<string, string>> GetHTML(string ticker)
var config = Configuration.Default.WithDefaultLoader();
var context = BrowsingContext.New(config);
var document = await context.OpenAsync($"https://sg.finance.yahoo.com/quote/{ticker}/");
float currentPx;

var quoteSummaryListItems = document.QuerySelectorAll("div[id='quote-summary'] td");
var quoteHeaderInfo = document.QuerySelectorAll("div[id='quote-header-info'] div span");
var quoteHeaderInfo = document.QuerySelectorAll("div[id='quote-header-info'] div span");

foreach (var item in quoteSummaryListItems.Select((sli, i) => new { Value = sli, Index = i }))
{
Expand All @@ -93,7 +104,7 @@ private static async Task<Dictionary<string, string>> GetHTML(string ticker)
{
// TODO: We should find a better identifier for current price instead if possible
var tmp = item.Value.InnerHtml;
if (float.TryParse(tmp, out currentPx))
if (float.TryParse(tmp, out float currentPx))
{
quoteSummary.Add("CURRENT PRICE", tmp);
break;
Expand Down
5 changes: 5 additions & 0 deletions StockScraper/StockScraper/StockScraper.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
<Reference Include="ExcelDna.Registration, Version=1.1.0.0, Culture=neutral, PublicKeyToken=f225e9659857edbe, processorArchitecture=MSIL">
<HintPath>..\packages\ExcelDna.Registration.1.1.0\lib\net40\ExcelDna.Registration.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
Expand All @@ -63,6 +66,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AddIn.cs" />
<Compile Include="MarketData\MdFtx.cs" />
<Compile Include="Scraper.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
Expand All @@ -72,6 +76,7 @@
<None Include="packages.config" />
<None Include="Properties\ExcelDna.Build.props" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\ExcelDna.AddIn.1.1.1\build\ExcelDna.AddIn.targets" Condition="Exists('..\packages\ExcelDna.AddIn.1.1.1\build\ExcelDna.AddIn.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
Expand Down
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions StockScraper/StockScraper/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<package id="ExcelDna.Integration" version="1.1.0" targetFramework="net48" />
<package id="ExcelDna.IntelliSense" version="1.3.0" targetFramework="net48" />
<package id="ExcelDna.Registration" version="1.1.0" targetFramework="net48" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.7.1" targetFramework="net48" />
<package id="System.Text.Encoding.CodePages" version="4.7.1" targetFramework="net48" />
</packages>

0 comments on commit c4651c9

Please sign in to comment.