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 + } }