Created
May 4, 2021 15:14
-
-
Save NVentimiglia/2268e94b64dfe187a5907f20fbc9848b to your computer and use it in GitHub Desktop.
TDAmeritrade SignIn Api DotNetCore / C#
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.Diagnostics; | |
using System.IO; | |
using System.Net; | |
using System.Net.Http; | |
using System.Runtime.InteropServices; | |
using System.Text.Json; | |
using System.Threading.Tasks; | |
using System.Web; | |
namespace TDConsole | |
{ | |
[Serializable] | |
public class SignInResult | |
{ | |
public string consumer_key { get; set; } | |
public string security_code { get; set; } | |
public string access_token { get; set; } | |
public string refresh_token { get; set; } | |
public string scope { get; set; } | |
public int expires_in { get; set; } | |
public int refresh_token_expires_in { get; set; } | |
public string token_type { get; set; } | |
} | |
/// <summary> | |
/// https://www.reddit.com/r/algotrading/comments/c81vzq/td_ameritrade_api_access_2019_guide/ | |
/// https://www.reddit.com/r/algotrading/comments/914q22/successful_access_to_td_ameritrade_api/ | |
/// </summary> | |
public class TDClient | |
{ | |
private const string RESULTFILE = "SignInResult.json"; | |
public string ConsumerKey = ""; | |
public string RedirectUri = "http://localhost"; | |
//("Paste from code={code} address bar result in step 1") | |
public string SecurityCode = ""; | |
public SignInResult Result; | |
public TDClient() | |
{ | |
Load(); | |
} | |
private void Load() | |
{ | |
if (!File.Exists(RESULTFILE)) | |
{ | |
using (var s = File.Create(RESULTFILE)) { } | |
} | |
var json = File.ReadAllText(RESULTFILE); | |
if (string.IsNullOrEmpty(json)) | |
{ | |
Result = new SignInResult(); | |
} | |
else | |
{ | |
Result = JsonSerializer.Deserialize<SignInResult>(json); | |
ConsumerKey = Result.consumer_key; | |
SecurityCode = Result.security_code; | |
} | |
} | |
private void Save() | |
{ | |
if (!File.Exists(RESULTFILE)) | |
{ | |
using (var s = File.Create(RESULTFILE)) { } | |
} | |
var json = JsonSerializer.Serialize(Result); | |
File.WriteAllText(RESULTFILE, json); | |
} | |
public void StartSignIn() | |
{ | |
var encodedKey = HttpUtility.UrlEncode(ConsumerKey); | |
var encodedUri = HttpUtility.UrlEncode(RedirectUri); | |
var path = $"https://auth.tdameritrade.com/auth?response_type=code&redirect_uri={encodedUri}&client_id={encodedKey}%40AMER.OAUTHAP"; | |
OpenBrowser(path); | |
} | |
public async Task CompleteSignIn() | |
{ | |
var decoded = HttpUtility.UrlDecode(SecurityCode); | |
var path = "https://api.tdameritrade.com/v1/oauth2/token"; | |
using (var client = new HttpClient()) | |
{ | |
var dict = new Dictionary<string, string> | |
{ | |
{ "grant_type", "authorization_code" }, | |
{ "access_type", "offline" }, | |
{ "client_id", $"{ConsumerKey}@AMER.OAUTHAP" }, | |
{ "redirect_uri", RedirectUri }, | |
{ "code", decoded } | |
}; | |
var req = new HttpRequestMessage(HttpMethod.Post, path) { Content = new FormUrlEncodedContent(dict) }; | |
var res = await client.SendAsync(req); | |
switch (res.StatusCode) | |
{ | |
case HttpStatusCode.OK: | |
var r = await res.Content.ReadAsStringAsync(); | |
Console.WriteLine(r); | |
Result = JsonSerializer.Deserialize<SignInResult>(r); | |
Result.security_code = SecurityCode; | |
Result.consumer_key = ConsumerKey; | |
Save(); | |
break; | |
default: | |
Console.WriteLine("Error: " + res.ReasonPhrase); | |
break; | |
} | |
} | |
} | |
public async Task RefreshSignIn() | |
{ | |
var decoded = HttpUtility.UrlDecode(Result.security_code); | |
var path = "https://api.tdameritrade.com/v1/oauth2/token"; | |
var dict = new Dictionary<string, string> | |
{ | |
{ "grant_type", "refresh_token" }, | |
{ "access_type", "" }, | |
{ "client_id", $"{Result.consumer_key}@AMER.OAUTHAP" }, | |
{ "redirect_uri", RedirectUri }, | |
{ "refresh_token", Result.refresh_token }, | |
{ "code", decoded } | |
}; | |
var req = new HttpRequestMessage(HttpMethod.Post, path) { Content = new FormUrlEncodedContent(dict) }; | |
using (var client = new HttpClient()) | |
{ | |
var res = await client.SendAsync(req); | |
switch (res.StatusCode) | |
{ | |
case HttpStatusCode.OK: | |
var r = await res.Content.ReadAsStringAsync(); | |
Console.WriteLine(r); | |
var result = JsonSerializer.Deserialize<SignInResult>(r); | |
Result.access_token = result.access_token; | |
Save(); | |
break; | |
default: | |
Console.WriteLine("Error: " + res.ReasonPhrase); | |
break; | |
} | |
} | |
} | |
public async Task GetQuote() | |
{ | |
var symbol = "SPY"; | |
var key = HttpUtility.UrlEncode(ConsumerKey); | |
var path = $"https://api.tdameritrade.com/v1/marketdata/{symbol}/quotes?apikey={key}"; | |
using (var client = new HttpClient()) | |
{ | |
var res = await client.GetAsync(path); | |
switch (res.StatusCode) | |
{ | |
case HttpStatusCode.OK: | |
var r = await res.Content.ReadAsStringAsync(); | |
Console.WriteLine(r); | |
break; | |
default: | |
Console.WriteLine("Error: " + res.ReasonPhrase); | |
break; | |
} | |
} | |
} | |
static void OpenBrowser(string url) | |
{ | |
try | |
{ | |
Process.Start(url); | |
} | |
catch | |
{ | |
// hack because of this: https://github.com/dotnet/corefx/issues/10361 | |
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | |
{ | |
url = url.Replace("&", "^&"); | |
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true }); | |
} | |
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) | |
{ | |
Process.Start("xdg-open", url); | |
} | |
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) | |
{ | |
Process.Start("open", url); | |
} | |
else | |
{ | |
throw; | |
} | |
} | |
} | |
} | |
class Program | |
{ | |
static async Task Main(string[] args) | |
{ | |
Console.WriteLine("Starting Client"); | |
Console.WriteLine("..."); | |
var client = new TDClient(); | |
Console.WriteLine("1 to sign in fresh, 2 to refresh signin"); | |
var option = Console.ReadKey(); | |
switch (option.Key) | |
{ | |
case ConsoleKey.D1: | |
Console.WriteLine("Paste consumer key :"); | |
client.ConsumerKey = Console.ReadLine(); | |
Console.WriteLine("Opening Browser. Please sign in."); | |
client.StartSignIn(); | |
Console.WriteLine("Paste the code. This is in the browser url bar 'code={code}'."); | |
client.SecurityCode = Console.ReadLine(); | |
await client.CompleteSignIn(); | |
break; | |
case ConsoleKey.D2: | |
await client.RefreshSignIn(); | |
break; | |
default: | |
return; | |
} | |
await client.GetQuote(); | |
Console.ReadKey(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment