Has anyone gotten the TD Ameritrade streaming API to work with C#? They have some documentation and JavaScript examples here https://developer.tdameritrade.com/content/streaming-data. I have gotten the JavaScript examples to work on https://js.do/, but can't get anything similar to work in .NET. This is a shortened version of what I'm trying to do. I can't include exactly what I'm sending because I'm trying to send the login message which includes account information, but I can say that I copy and pasted the exact JSON message that is working in my JavaScript tests into the file LoginJSON.txt in this example. In this example the socket will just close as soon as I send the message, no text response at all. If however I send an intentionally malformatted message I'll actually get text response saying the message is malformatted and then get a socket disconnect. Their support has been non-responsive which I understand to the the norm. There are some python examples here https://www.youtube.com/channel/UCBsTB02yO0QGwtlfiv5m25Q, but I've watched them all and haven't learned anything to help me get my code working.
ClientWebSocket socket = new ClientWebSocket();
var connectAsync = socket.ConnectAsync(new Uri("wss://streamer-ws.tdameritrade.com/ws"), CancellationToken.None);
string loginRequest;
using (StreamReader re = new StreamReader("LoginJSON.txt")) {
loginRequest = re.ReadToEnd();
}
connectAsync.Wait();
Thread readThread = new Thread(
delegate(object obj)
{
while (true) {
if (socket.State == WebSocketState.Open) {
Console.Out.WriteLine("Waiting");
byte[] recBytes = new byte[1024];
var clientBuffer = new ArraySegment<byte>(recBytes);
var receiveAsync = socket.ReceiveAsync(clientBuffer, CancellationToken.None);
receiveAsync.Wait();
switch (receiveAsync.Result.MessageType) {
case WebSocketMessageType.Text:
var s = Encoding.UTF8.GetString(recBytes);
Console.Out.WriteLine(s.Trim());
break;
case WebSocketMessageType.Close:
Console.Out.WriteLine("Close message received");
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
});
readThread.Start();
socket.SendAsync(Encoding.UTF8.GetBytes(loginRequest), WebSocketMessageType.Text, true, CancellationToken.None);
Console.ReadLine();
I faced the same problem and I managed to solve it. In my case, the timestamp was not prepared correctly, it is necessary to calculate the timestamp to get the TokenTimestamp property, which should be converted to universal time. Sorry for my english from google translate. :) Here is the correct code:
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime tokenDate = Convert.ToDateTime(userPrincipal.StreamerInfo.TokenTimestamp);
TimeSpan tokenEpoch = tokenDate.ToUniversalTime() - epoch;
long timestamp = (long)Math.Floor(tokenEpoch.TotalMilliseconds);
var credentials = new Credentials
{
userid = userPrincipal.Accounts[0].AccountId,
token = userPrincipal.StreamerInfo.Token,
company = userPrincipal.Accounts[0].Company,
segment = userPrincipal.Accounts[0].Segment,
cddomain = userPrincipal.Accounts[0].AccountCdDomainId,
usergroup = userPrincipal.StreamerInfo.UserGroup,
accesslevel = userPrincipal.StreamerInfo.AccessLevel,
authorized = "Y",
timestamp = timestamp,
appid = userPrincipal.StreamerInfo.AppId,
acl = userPrincipal.StreamerInfo.Acl
};
var credentialArr = credentials.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Select(p => new KeyValuePair<string, string>(p.Name, p.GetValue(credentials, null).ToString()));
var loginRequest = new Request
{
service = "ADMIN",
command = "LOGIN",
requestid = "0",
account = userPrincipal.Accounts[0].AccountId,
source = userPrincipal.StreamerInfo.AppId,
parameters = new Parameters
{
credential = string.Join("&", credentialArr.Where(c => !string.IsNullOrWhiteSpace(c.Value)).Select(c => string.Format("{0}={1}", HttpUtility.UrlEncode(c.Key, Encoding.UTF8), HttpUtility.UrlEncode(c.Value, Encoding.UTF8)))),
token = userPrincipal.StreamerInfo.Token,
version = "1.0",
qoslevel = "0"
}
};
var req = JsonConvert.SerializeObject(Requests.ToRequests(loginRequest), Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
socketClient = new WebSocket(string.Format("wss://{0}/ws", userPrincipal.StreamerInfo.StreamerSocketUrl));
if(Environment.OSVersion.Version.Major > 5)
{
socketClient.SslConfiguration.EnabledSslProtocols = (System.Security.Authentication.SslProtocols)3072;
socketClient.SslConfiguration.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
}
socketClient.Connect();
socketClient.Send(req);