diff --git a/TDAmeritrade/Models/TDMiscModels.cs b/TDAmeritrade/Models/TDMiscModels.cs
new file mode 100644
index 0000000..179df70
--- /dev/null
+++ b/TDAmeritrade/Models/TDMiscModels.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace TDAmeritrade
+{
+ [Serializable]
+ public enum MarketTypes
+ {
+ BOND, EQUITY, ETF, FOREX, FUTURE, FUTURE_OPTION, INDEX, INDICAT, MUTUAL_FUND, OPTION, UNKNOWN
+ }
+}
diff --git a/TDAmeritrade/Models/TDOptionChainModels.cs b/TDAmeritrade/Models/TDOptionChainModels.cs
index fd4c471..63e85c7 100644
--- a/TDAmeritrade/Models/TDOptionChainModels.cs
+++ b/TDAmeritrade/Models/TDOptionChainModels.cs
@@ -1,4 +1,5 @@
using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
@@ -74,7 +75,6 @@ public enum TDOptionChainRanges
SNK,
}
-
[Serializable]
public class TDOptionChainRequest
{
@@ -85,7 +85,7 @@ public class TDOptionChainRequest
///
/// The number of strikes to return above and below the at-the-money price.
///
- public int strikeCount { get; set; }
+ public int? strikeCount { get; set; }
///
/// Passing a value returns a Strategy Chain
///
@@ -93,20 +93,20 @@ public class TDOptionChainRequest
///
/// Type of contracts to return in the chai
///
- public TDOptionChainTypes contractType { get; set; }
+ public TDOptionChainTypes? contractType { get; set; }
///
/// Only return expirations after this date
///
- public double fromDate { get; set; }
+ public DateTime? fromDate { get; set; }
///
/// Only return expirations before this date
///
- public double toDate { get; set; }
+ public DateTime? toDate { get; set; }
///
/// Strike interval for spread strategy chains
///
- public double interval {get;set; }
+ public double? interval {get;set; }
///
/// Provide a strike price to return options only at that strike price.
///
@@ -130,11 +130,11 @@ public class TDOptionChainRequest
///
/// Days to expiration to use in calculations. Applies only to ANALYTICAL strategy chains
///
- public int daysToExpiration { get; set; }
+ public int? daysToExpiration { get; set; }
///
/// Return only options expiring in the specified month
///
- public string expMonth { get; set; } = "ALL";
+ public string expMonth { get; set; }
///
/// Include quotes for options in the option chain. Can be TRUE or FALSE. Default is FALSE.
///
@@ -143,34 +143,6 @@ public class TDOptionChainRequest
/// Type of contracts to return
///
public TDOptionChainOptionTypes optionType { get; set; }
-
-
- [JsonIgnore]
- public DateTime FromDate
- {
- get
- {
- return TDHelpers.FromUnixTimeSeconds(fromDate);
- }
- set
- {
- fromDate = TDHelpers.ToUnixTimeSeconds(value);
- }
- }
-
-
- [JsonIgnore]
- public DateTime ToDate
- {
- get
- {
- return TDHelpers.FromUnixTimeSeconds(toDate);
- }
- set
- {
- toDate = TDHelpers.ToUnixTimeSeconds(value);
- }
- }
}
[Serializable]
@@ -187,19 +159,119 @@ public class TDOptionChain
public int interestRate { get; set; }
public int underlyingPrice { get; set; }
public int volatility { get; set; }
- public string callExpDateMap { get; set; }
- public string putExpDateMap { get; set; }
+
+ public List callExpDateMap { get; set; }
+ public List putExpDateMap { get; set; }
+ }
+
+ public class TDOptionChainConverter : JsonConverter
+ {
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType == typeof(TDOptionChain);
+ }
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ var doc = JObject.Load(reader);
+ var model = new TDOptionChain();
+ model.symbol = doc["symbol"].Value();
+ model.status = doc["status"].Value();
+ model.underlying = doc["underlying"].ToObject();
+ model.strategy = doc["strategy"].Value();
+ model.interval = doc["interval"].Value();
+ model.isDelayed = doc["isDelayed"].Value();
+ model.isIndex = doc["isIndex"].Value();
+ model.daysToExpiration = doc["daysToExpiration"].Value();
+ model.interestRate = doc["interestRate"].Value();
+ model.underlyingPrice = doc["underlyingPrice"].Value();
+ model.volatility = doc["volatility"].Value();
+ model.callExpDateMap = GetMap(doc["callExpDateMap"].ToObject());
+ model.putExpDateMap = GetMap(doc["putExpDateMap"].ToObject());
+ return model;
+ }
+
+ public List GetMap(JObject doc)
+ {
+ var map = new List();
+
+ foreach (var expiry in doc.Properties())
+ {
+ var exp = new TDOptionMap();
+ map.Add(exp);
+ exp.expires = DateTime.Parse(expiry.Name.Split(":")[0]);
+ exp.options = new List();
+
+ var set = expiry.Value.ToObject();
+ foreach (var contract in set.Properties())
+ {
+ var stike = double.Parse(contract.Name);
+ var tuples = contract.Value.First.ToObject();
+ var option = new TDOption();
+ option.strike = stike;
+ exp.options.Add(option);
+
+ option.putCall = tuples["putCall"].Value();
+ option.symbol = tuples["symbol"].Value();
+ option.description = tuples["description"].Value();
+ option.exchangeName = tuples["exchangeName"].Value();
+ option.bidPrice = tuples["bid"].Value();
+ option.askPrice = tuples["ask"].Value();
+ option.lastPrice = tuples["last"].Value();
+ option.markPrice = tuples["mark"].Value();
+ option.bidSize = tuples["bidSize"].Value();
+ option.askSize = tuples["askSize"].Value();
+ option.lastSize = tuples["lastSize"].Value();
+ option.highPrice = tuples["highPrice"].Value();
+ option.lowPrice = tuples["lowPrice"].Value();
+ option.openPrice = tuples["openPrice"].Value();
+ option.closePrice = tuples["closePrice"].Value();
+ option.totalVolume = tuples["totalVolume"].Value();
+ option.quoteTimeInLong = tuples["quoteTimeInLong"].Value();
+ option.tradeTimeInLong = tuples["tradeTimeInLong"].Value();
+ option.netChange = tuples["netChange"].Value();
+ option.volatility = tuples["volatility"].Value();
+ option.delta = tuples["delta"].Value();
+ option.gamma = tuples["gamma"].Value();
+ option.theta = tuples["theta"].Value();
+ option.vega = tuples["vega"].Value();
+ option.rho = tuples["rho"].Value();
+ option.timeValue = tuples["timeValue"].Value();
+ option.openInterest = tuples["openInterest"].Value();
+ option.isInTheMoney = tuples["inTheMoney"].Value();
+ option.theoreticalOptionValue = tuples["theoreticalOptionValue"].Value();
+ option.theoreticalVolatility = tuples["theoreticalVolatility"].Value();
+ option.strikePrice = tuples["strikePrice"].Value();
+ option.expirationDate = tuples["expirationDate"].Value();
+ option.multiplier = tuples["multiplier"].Value();
+ option.settlementType = tuples["settlementType"].Value();
+ option.deliverableNote = tuples["deliverableNote"].Value();
+ option.percentChange = tuples["percentChange"].Value();
+ option.markChange = tuples["markChange"].Value();
+ option.markPercentChange = tuples["markPercentChange"].Value();
+
+ }
+ }
+ return map;
+ }
+
}
+
[Serializable]
- public class TDOptionDeliverablesList
+ public class TDOptionMap
{
- public string symbol { get; set; }
- public string assetType { get; set; }
- public string deliverableUnits { get; set; }
- public string currencyType { get; set; }
+ public DateTime expires { get; set; }
+
+ public List options { get; set; }
}
+
+
[Serializable]
public class TDOption
{
@@ -207,73 +279,71 @@ public class TDOption
public string symbol { get; set; }
public string description { get; set; }
public string exchangeName { get; set; }
- public int bidPrice { get; set; }
- public int askPrice { get; set; }
- public int lastPrice { get; set; }
- public int markPrice { get; set; }
+ public double strike { get; set; }
+ public double bidPrice { get; set; }
+ public double askPrice { get; set; }
+ public double lastPrice { get; set; }
+ public double markPrice { get; set; }
public int bidSize { get; set; }
public int askSize { get; set; }
public int lastSize { get; set; }
- public int highPrice { get; set; }
- public int lowPrice { get; set; }
- public int openPrice { get; set; }
- public int closePrice { get; set; }
+ public double highPrice { get; set; }
+ public double lowPrice { get; set; }
+ public double openPrice { get; set; }
+ public double closePrice { get; set; }
public int totalVolume { get; set; }
- public int quoteTimeInLong { get; set; }
- public int tradeTimeInLong { get; set; }
- public int netChange { get; set; }
- public int volatility { get; set; }
- public int delta { get; set; }
- public int gamma { get; set; }
- public int theta { get; set; }
- public int vega { get; set; }
- public int rho { get; set; }
- public int timeValue { get; set; }
+ public long quoteTimeInLong { get; set; }
+ public long tradeTimeInLong { get; set; }
+
+ public double netChange { get; set; }
+ public double volatility { get; set; }
+ public double delta { get; set; }
+ public double gamma { get; set; }
+ public double theta { get; set; }
+ public double vega { get; set; }
+ public double rho { get; set; }
+ public double timeValue { get; set; }
public int openInterest { get; set; }
public bool isInTheMoney { get; set; }
- public int theoreticalOptionValue { get; set; }
- public int theoreticalVolatility { get; set; }
- public bool isMini { get; set; }
- public bool isNonStandard { get; set; }
- public List optionDeliverablesList { get; set; }
- public int strikePrice { get; set; }
+ public double theoreticalOptionValue { get; set; }
+ public double theoreticalVolatility { get; set; }
+ public double strikePrice { get; set; }
public string expirationDate { get; set; }
public string expirationType { get; set; }
- public int multiplier { get; set; }
+ public double multiplier { get; set; }
public string settlementType { get; set; }
public string deliverableNote { get; set; }
- public bool isIndexOption { get; set; }
- public int percentChange { get; set; }
- public int markChange { get; set; }
- public int markPercentChange { get; set; }
+ public double percentChange { get; set; }
+ public double markChange { get; set; }
+ public double markPercentChange { get; set; }
}
[Serializable]
public class TDUnderlying
{
- public int ask { get; set; }
+ public double ask { get; set; }
public int askSize { get; set; }
- public int bid { get; set; }
+ public double bid { get; set; }
public int bidSize { get; set; }
- public int change { get; set; }
- public int close { get; set; }
+ public double change { get; set; }
+ public double close { get; set; }
public bool delayed { get; set; }
public string description { get; set; }
public string exchangeName { get; set; }
- public int fiftyTwoWeekHigh { get; set; }
- public int fiftyTwoWeekLow { get; set; }
- public int highPrice { get; set; }
- public int last { get; set; }
- public int lowPrice { get; set; }
- public int mark { get; set; }
- public int markChange { get; set; }
- public int markPercentChange { get; set; }
- public int openPrice { get; set; }
- public int percentChange { get; set; }
- public int quoteTime { get; set; }
+ public double fiftyTwoWeekHigh { get; set; }
+ public double fiftyTwoWeekLow { get; set; }
+ public double highPrice { get; set; }
+ public double last { get; set; }
+ public double lowPrice { get; set; }
+ public double mark { get; set; }
+ public double markChange { get; set; }
+ public double markPercentChange { get; set; }
+ public double openPrice { get; set; }
+ public double percentChange { get; set; }
+ public double quoteTime { get; set; }
public string symbol { get; set; }
public int totalVolume { get; set; }
- public int tradeTime { get; set; }
+ public double tradeTime { get; set; }
}
diff --git a/TDAmeritrade/Models/TDPriceHistoryModels.cs b/TDAmeritrade/Models/TDPriceHistoryModels.cs
index 7eeb1f8..8b14da5 100644
--- a/TDAmeritrade/Models/TDPriceHistoryModels.cs
+++ b/TDAmeritrade/Models/TDPriceHistoryModels.cs
@@ -1,12 +1,10 @@
using Newtonsoft.Json;
using System;
-using System.Collections.Generic;
-using System.Linq;
namespace TDAmeritrade
{
[Serializable]
- public struct TDPriceCandle
+ public struct TDPriceCandle : IBitModel
{
public double close { get; set; }
public double datetime { get; set; }
@@ -27,6 +25,16 @@ public DateTime DateTime
datetime = TDHelpers.ToUnixTimeSeconds(value);
}
}
+
+ public void Parse(BitSerializer stream)
+ {
+ datetime = stream.Parse(datetime);
+ open = stream.Parse(open);
+ low = stream.Parse(low);
+ high = stream.Parse(high);
+ close = stream.Parse(close);
+ volume = stream.Parse(volume);
+ }
}
diff --git a/TDAmeritrade/TDAmeritradeClient.cs b/TDAmeritrade/TDAmeritradeClient.cs
index bbbc07f..3a55c5b 100644
--- a/TDAmeritrade/TDAmeritradeClient.cs
+++ b/TDAmeritrade/TDAmeritradeClient.cs
@@ -191,7 +191,7 @@ public async Task GetOptionsChain(TDOptionChainRequest request)
var json = await GetOptionsChainJson(request);
if (!IsNullOrEmpty(json))
{
- return JsonConvert.DeserializeObject(json);
+ return JsonConvert.DeserializeObject(json, new TDOptionChainConverter());
}
return null;
}
@@ -213,18 +213,35 @@ public async Task GetOptionsChainJson(TDOptionChainRequest request)
queryString.Add("apikey", AuthResult.consumer_key);
}
queryString.Add("symbol", request.symbol);
- queryString.Add("contractType", request.contractType.ToString());
- queryString.Add("strikeCount", request.strikeCount.ToString());
+ if (request.contractType.HasValue)
+ {
+ queryString.Add("contractType", request.contractType.ToString());
+ }
+ if (request.strikeCount.HasValue)
+ {
+ queryString.Add("strikeCount", request.strikeCount.ToString());
+ }
queryString.Add("includeQuotes", request.includeQuotes ? "FALSE" : "TRUE");
- queryString.Add("strategy", request.strategy.ToString());
- queryString.Add("interval", request.interval.ToString());
+ if (request.interval.HasValue)
+ {
+ queryString.Add("interval", request.interval.ToString());
+ }
if (request.strike.HasValue)
{
queryString.Add("strike", request.strike.Value.ToString());
}
- queryString.Add("fromDate", request.fromDate.ToString("yyyy-MM-dd"));
- queryString.Add("toDate", request.toDate.ToString("yyyy-MM-dd"));
- queryString.Add("expMonth", request.expMonth);
+ if (request.fromDate.HasValue)
+ {
+ queryString.Add("fromDate", request.fromDate.Value.ToString("yyyy-MM-dd"));
+ }
+ if (request.toDate.HasValue)
+ {
+ queryString.Add("toDate", request.toDate.Value.ToString("yyyy-MM-dd"));
+ }
+ if (!string.IsNullOrEmpty(request.expMonth))
+ {
+ queryString.Add("expMonth", request.expMonth);
+ }
queryString.Add("optionType", request.optionType.ToString());
if (request.strategy == TDOptionChainStrategy.ANALYTICAL)
@@ -237,7 +254,7 @@ public async Task GetOptionsChainJson(TDOptionChainRequest request)
var q = queryString.ToString();
- var path = $"https://api.tdameritrade.com/v1/marketdata/chains{q}";
+ var path = $"https://api.tdameritrade.com/v1/marketdata/chains?{q}";
using (var client = new HttpClient())
{
@@ -419,16 +436,13 @@ public async Task GetPrincipals(params TDPrincipalsFields[] fields)
///
public async Task GetPrincipalsJson(params TDPrincipalsFields[] fields)
{
-
- if (!HasConsumerKey)
+ if (!IsSignedIn)
{
- throw (new Exception("ConsumerKey is null"));
+ throw (new Exception("Not authenticated"));
}
var arg = string.Join(",", fields.Select(o => o.ToString()));
- var key = HttpUtility.UrlEncode(AuthResult.consumer_key);
-
var path = $"https://api.tdameritrade.com/v1/userprincipals?fields={arg}";
using (var client = new HttpClient())
@@ -446,5 +460,43 @@ public async Task GetPrincipalsJson(params TDPrincipalsFields[] fields)
}
}
#endregion
+
+ #region Misc
+
+ ///
+ /// Retrieve market hours for specified single market
+ ///
+ public async Task GetMarketHoursJson(MarketTypes type, DateTime day)
+ {
+ if (!IsSignedIn)
+ {
+ throw (new Exception("ConsumerKey is null"));
+ }
+
+ var key = HttpUtility.UrlEncode(AuthResult.consumer_key);
+
+ string path = IsSignedIn
+ ? $"https://api.tdameritrade.com/v1/marketdata/{type}/hours?date={day.ToShortDateString()}"
+ : $"https://api.tdameritrade.com/v1/marketdata/{type}/hours?apikey={key}&date={day.ToShortDateString()}";
+
+ using (var client = new HttpClient())
+ {
+ if (IsSignedIn)
+ {
+ client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthResult.access_token);
+ }
+ var res = await client.GetAsync(path);
+
+ switch (res.StatusCode)
+ {
+ case HttpStatusCode.OK:
+ return await res.Content.ReadAsStringAsync();
+ default:
+ throw (new Exception($"{res.StatusCode} {res.ReasonPhrase}"));
+ }
+ }
+ }
+ #endregion
+
}
}