Skip to content

Instantly share code, notes, and snippets.

@NVentimiglia
Created May 4, 2021 15:14
Show Gist options
  • Save NVentimiglia/2268e94b64dfe187a5907f20fbc9848b to your computer and use it in GitHub Desktop.
Save NVentimiglia/2268e94b64dfe187a5907f20fbc9848b to your computer and use it in GitHub Desktop.
TDAmeritrade SignIn Api DotNetCore / C#
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