public static string AsString(FutureType f) { switch (f) { case FutureType.ThisWeek: return("this_week"); case FutureType.NextWeek: return("next_week"); case FutureType.Quarter: return("quarter"); } throw new ArgumentException("Unknown FutureType: " + f); }
// Throws on HTTP timeouts, HTTP errors, parse errors and // application errors (when OkCoin gives us error_code). public Dictionary <FutureType, List <FuturePosition> > FuturePositions(Currency currency, CoinType coin) { try { var param = new KV[] { new KV("symbol", Serialization.AsString(coin, currency)), new KV("type", "1"), }; string content = SendRequest(HttpMethod.Post, "future_position_4fix.do", Authenticated(param)); var root = JObject.Parse(content); CheckErrorCode(root); var res = new Dictionary <FutureType, List <FuturePosition> >(); foreach (var e in Util.Enum.Values <FutureType>()) { res.Add(e, new List <FuturePosition>()); } foreach (JObject data in (JArray)root["holding"]) { Action <PositionType, string> AddPosition = (PositionType type, string prefix) => { var quantity = data[prefix + "_amount"].AsDecimal(); if (quantity == 0) { return; } FutureType ft = Serialization.ParseFutureType((string)data["contract_type"]); string contractId = (string)data["contract_id"]; VerifyFutureType(ft, contractId); res[ft].Add(new FuturePosition() { Quantity = quantity, PositionType = type, AvgPrice = data[prefix + "_price_avg"].AsDecimal(), ContractId = contractId, Leverage = Serialization.ParseLeverage((string)data["lever_rate"]), }); }; AddPosition(PositionType.Long, "buy"); AddPosition(PositionType.Short, "sell"); } return(res); } catch (Exception e) { _log.Warn(e, "RestClient.FuturePosition() failed"); throw; } }
// Verifies that FutureTypeFromContractId(contractId) matches `actual`. void VerifyFutureType(FutureType actual, string contractId) { DateTime now = DateTime.UtcNow; FutureType deduced = Settlement.FutureTypeFromContractId(contractId, now - TimeSpan.FromMinutes(1)); // FutureTypeFromContractId() is unreliable very close to settlement time. // If it gives us the same value at now - 1m and now + 1m, we expect the actual contract_type set // by the exchange to be equal to what we deduce from contract_id. If it's not the case, it means our // algorithm is broken and the positions received from WebSocket can't be trusted. if (deduced != actual && deduced == Settlement.FutureTypeFromContractId(contractId, now + TimeSpan.FromMinutes(2))) { _log.Fatal("Unexpected {{contract_type, contract_id}} pair: {{{0}, {1}}}. Expected contract_type: {2}.", actual, contractId, deduced); } }
/// <summary> /// Private method which exposes all possible parameters, with default values for the optional ones. /// </summary> /// <param name="category">Category=StockOption, IndexOption, FutureOption or CurrencyOption</param> /// <param name="symbolRoot">Symbol root. Required Field, the symbol the option is a derivative of, this search will not return options based on a partial root.</param> /// <param name="strikeCount">Number of strikes prices above and below the underlying price. Defaults to 3. Ignored if strike price high and low are passed.</param> /// <param name="strikePriceLow">Strike price low</param> /// <param name="strikePriceHigh">Strike price high</param> /// <param name="dateCount">Number of expiration dates. Default value 3. Ignored if expiration dates high and low are passed.</param> /// <param name="expirationDateLow">Expiration date low</param> /// <param name="expirationDateHigh">Expiration date high</param> /// <param name="optionType">Option type (Both, Call, Put) Default: Both</param> /// <param name="futureType">Future type (Electronic, Pit) Default: Electronic</param> /// <param name="symbolType">SymbolType (Both, Composite, Regional) Default: Composite</param> /// <param name="country">Country code (US, DE, CA) Default: US</param> /// <returns></returns> public static string GetOptionSearchCriteria(SearchCategory category, string symbolRoot, uint strikeCount = 3, decimal strikePriceLow = 0, decimal strikePriceHigh = decimal.MaxValue, uint dateCount = 3, DateTime?expirationDateLow = null, DateTime?expirationDateHigh = null, OptionType optionType = OptionType.Both, FutureType futureType = FutureType.Electronic, SymbolType symbolType = SymbolType.Composite, CountryCode country = CountryCode.US) { if (string.IsNullOrEmpty(symbolRoot)) { throw new ArgumentException("symbolRoot is required.", "symbolRoot"); } if (GetAssetType(category) != AssetClass.Option) { throw new ArgumentException("SearchCategory must be StockOption, IndexOption, FutureOption or CurrencyOption", "category"); } if (strikePriceLow < 0) { throw new ArgumentOutOfRangeException("strikePriceLow", "Argument cannot be less than 0."); } if (strikePriceHigh < 0) { throw new ArgumentOutOfRangeException("strikePriceHigh", "Argument cannot be less than 0."); } if ((expirationDateLow.HasValue && !expirationDateHigh.HasValue) || (expirationDateHigh.HasValue && !expirationDateLow.HasValue)) { throw new ArgumentException("If either expiration date parameter is passed, both must be passed."); } if (expirationDateHigh.HasValue && expirationDateLow.HasValue && expirationDateHigh < expirationDateLow) { throw new ArgumentOutOfRangeException("expirationDateHigh", "expirationDateHigh cannot be before expirationDateLow."); } StringBuilder criteria = new StringBuilder(255); Append(criteria, "c=" + category.ToString()); Append(criteria, "R=" + symbolRoot); // strike price range takes precidence over strike count if (strikePriceLow > 0 && strikePriceHigh < decimal.MaxValue) { Append(criteria, "Spl=" + strikePriceLow); Append(criteria, "Sph=" + strikePriceHigh); } else if (strikeCount != 3) { Append(criteria, "Stk=" + strikeCount); } // daterange takes precidence over datacount if (expirationDateLow.HasValue) { Append(criteria, "Edl=" + ((DateTime)expirationDateLow).ToString("MM-dd-yyyy")); Append(criteria, "Edh=" + ((DateTime)expirationDateHigh).ToString("MM-dd-yyyy")); } else if (dateCount != 3) { Append(criteria, "Exd=" + dateCount); } if (optionType != OptionType.Both) { Append(criteria, "OT=" + optionType.ToString()); } if (futureType != FutureType.Electronic) { Append(criteria, "FT=" + futureType.ToString()); } if (symbolType != SymbolType.Composite) { Append(criteria, "ST=" + symbolType.ToString()); } if (country != CountryCode.US) { Append(criteria, "Cnt=" + country.ToString()); } return(criteria.ToString()); }
public static string GetFutureSearchCriteria(string description = "", string root = "", FutureType futureType = FutureType.Electronic, Currency currency = Currency.USD, bool includeExpired = false, CountryCode country = CountryCode.ALL) { StringBuilder criteria = new StringBuilder(255); Append(criteria, "c=" + SearchCategory.Future.ToString()); if (description != string.Empty) { Append(criteria, "desc=" + description); } if (root != string.Empty) { Append(criteria, "r=" + root); } if (futureType != FutureType.Electronic) { Append(criteria, "FT=" + futureType.ToString()); } if (currency != Currency.USD) { Append(criteria, "Cur=" + currency.ToString()); } if (includeExpired) { Append(criteria, "Exp=true"); } if (country != CountryCode.ALL) { Append(criteria, "Cnt=" + country.ToString()); } return(criteria.ToString()); }
public IMessageIn Visit(FuturePositionsUpdate msg) { // "symbol": "btc_usd", // "positions": [ // { // "contract_id": "20160219013", // "contract_name": "BTC0219", // "avgprice": "413.15435805", // "balance": "0.04855328", // "bondfreez": "0", // "costprice": "413.15435805", // "eveningup": "2", // "forcedprice": "379.0405725", // "position": "1", // "profitreal": "-1.4522E-4", // "fixmargin": "0.04840806", // "hold_amount": "2", // "lever_rate": "10", // "position_id": "9018065" // }, // ] if (_data == null) { // OkCoin sends an empty message without data in response to // our subscription request. return(msg); } DateTime now = DateTime.UtcNow; string symbol = (string)_data["symbol"]; string[] parts = symbol.Split(new char[] { '_' }, 2); Condition.Requires(parts, "parts").HasLength(2); msg.CoinType = Serialization.ParseCoinType(parts[0]); msg.Currency = Serialization.ParseCurrency(parts[1]); msg.Positions = new List <FuturePosition>(); FutureType?futureType = null; Condition.Requires(_data["positions"], "positions").IsNotEmpty(); foreach (JToken elem in _data["positions"]) { string contractId = (string)elem["contract_id"]; // Figuring out FutureType around the time of settlement is tricky. // We assume the following: // 1. Our local time when parsing a message is less than one minute ahead of the server time // when the message was produced. Basically, latency + time skey must be under a minute. // 2. When settlement kicks in, trading is stopped for more than a minute plus time skew. // OkCoin docs say they stop all trading for around 10 minutes, so it seems reasonable. FutureType ft = Settlement.FutureTypeFromContractId(contractId, now - TimeSpan.FromMinutes(1)); if (futureType.HasValue && futureType.Value != ft) { throw new Exception(String.Format("Inconsistent FutureType: {0} vs {1}", futureType.Value, ft)); } futureType = ft; decimal quantity = elem["hold_amount"].AsDecimal(); if (quantity != 0) { msg.Positions.Add(new FuturePosition() { Leverage = Serialization.ParseLeverage((string)elem["lever_rate"]), PositionType = Serialization.ParsePositionType((string)elem["position"]), ContractId = contractId, Quantity = quantity, AvgPrice = elem["avgprice"].AsDecimal(), }); } } msg.FutureType = futureType.Value; return(msg); }
public static string GetFutureSearchCriteria(string description = "", string root = "", FutureType futureType = FutureType.Electronic, Currency currency = Currency.USD, bool includeExpired = false, CountryCode country = CountryCode.ALL) { StringBuilder criteria = new StringBuilder(255); Append(criteria, "c=" + SearchCategory.Future.ToString()); if (description != string.Empty) Append(criteria, "desc=" + description); if (root != string.Empty) Append(criteria, "r=" + root); if (futureType != FutureType.Electronic) Append(criteria, "FT=" + futureType.ToString()); if (currency != Currency.USD) Append(criteria, "Cur=" + currency.ToString()); if (includeExpired) Append(criteria, "Exp=true"); if (country != CountryCode.ALL) Append(criteria, "Cnt=" + country.ToString()); return criteria.ToString(); }
private void OptionSymbolSearchAsync(SearchCategory category, string symbolRoot, uint strikeCount = 3, decimal strikePriceLow = 0, decimal strikePriceHigh = decimal.MaxValue, uint dateCount = 3, DateTime? expirationDateLow = null, DateTime? expirationDateHigh = null, OptionType optionType = OptionType.Both, FutureType futureType = FutureType.Electronic, SymbolType symbolType = SymbolType.Composite, CountryCode country = CountryCode.US, int timeout = TimeoutDefault) { OptionSymbolSearchCompletedTask task = OptionSymbolSearch; AsyncCallback callback = OptionSymbolSearchCompletedCallback; task.BeginInvoke(category, symbolRoot, strikeCount, strikePriceLow, strikePriceHigh, dateCount, expirationDateLow, expirationDateHigh, optionType, futureType, symbolType, country, timeout, callback, null); }
public void OptionSymbolSearchAsync(SearchCategory category, string symbolRoot, decimal strikePriceLow, decimal strikePriceHigh, DateTime expirationDateLow, DateTime expirationDateHigh, OptionType optionType = OptionType.Both, FutureType futureType = FutureType.Electronic, SymbolType symbolType = SymbolType.Composite, CountryCode country = CountryCode.US, int timeout = TimeoutDefault) { // call full overload with all params (defaults) OptionSymbolSearchAsync(category, symbolRoot, 3, strikePriceLow, strikePriceHigh, 3, expirationDateLow, expirationDateHigh, optionType, futureType, symbolType, country, timeout); }
public void OptionSymbolSearchAsync(SearchCategory category, string symbolRoot, DateTime expirationDateLow, DateTime expirationDateHigh, uint strikeCount = 3, OptionType optionType = OptionType.Both, FutureType futureType = FutureType.Electronic, SymbolType symbolType = SymbolType.Composite, CountryCode country = CountryCode.US, int timeout = TimeoutDefault) { // call full overload with all params (defaults) // ReSharper disable RedundantArgumentName OptionSymbolSearchAsync(category: category, symbolRoot: symbolRoot, strikeCount: strikeCount, strikePriceLow: 0, strikePriceHigh: decimal.MaxValue, dateCount: 3, expirationDateLow: expirationDateLow, expirationDateHigh: expirationDateHigh, optionType: optionType, futureType: futureType, symbolType: symbolType, country: country, timeout: timeout); // ReSharper restore RedundantArgumentName }
/// <summary> /// Allows searching by strike range and date range. /// </summary> public List<Symbol> OptionSymbolSearch(SearchCategory category, string symbolRoot, decimal strikePriceLow, decimal strikePriceHigh, DateTime? expirationDateLow = null, DateTime? expirationDateHigh = null, OptionType optionType = OptionType.Both, FutureType futureType = FutureType.Electronic, SymbolType symbolType = SymbolType.Composite, CountryCode country = CountryCode.US, int timeout = TimeoutDefault) { // call full overload with all params (defaults) // ReSharper disable RedundantArgumentName return OptionSymbolSearch(category: category, symbolRoot: symbolRoot, strikeCount: 3, strikePriceLow: strikePriceLow, strikePriceHigh: strikePriceHigh, dateCount: 3, expirationDateLow: expirationDateLow, expirationDateHigh: expirationDateHigh, optionType: optionType, futureType: futureType, symbolType: symbolType, country: country, timeout: timeout); // ReSharper restore RedundantArgumentName }
/* Option Symbol Search can either be called by passing a combination of strikecount or strike range with a datacount or date range (4 possible combinations). The 4 public overloads expose this functionality. */ /// <summary> /// Allows searching by strike count and date count. /// </summary> public List<Symbol> OptionSymbolSearch(SearchCategory category, string symbolRoot, uint strikeCount = 3, uint dateCount = 3, OptionType optionType = OptionType.Both, FutureType futureType = FutureType.Electronic, SymbolType symbolType = SymbolType.Composite, CountryCode country = CountryCode.US, int timeout = TimeoutDefault) { // call full overload with all params (defaults) return OptionSymbolSearch(category, symbolRoot, strikeCount, 0, decimal.MaxValue, dateCount, null, null, optionType, futureType, symbolType, country, timeout); }
public void FutureSymbolSearchAsync(string description = "", string symbolRoot = "", FutureType futureType = FutureType.Electronic, Currency currency = Currency.USD, bool includeExpired = false, CountryCode country = CountryCode.ALL, int timeout = TimeoutDefault) { FutureSymbolSearchCompletedTask task = FutureSymbolSearch; AsyncCallback callback = FutureSymbolSearchCompletedCallback; task.BeginInvoke(description, symbolRoot, futureType, currency, includeExpired, country, timeout, callback, null); }
public List<Symbol> FutureSymbolSearch(string description = "", string symbolRoot = "", FutureType futureType = FutureType.Electronic, Currency currency = Currency.USD, bool includeExpired = false, CountryCode country = CountryCode.ALL, int timeout = TimeoutDefault) { //if (!IsAuthorized) throw new ClientAuthorizationException(); Uri uri = new Uri(root, string.Format("/v2/data/symbols/search/{0}", SymbolSearch.GetFutureSearchCriteria(description, symbolRoot, futureType, currency, includeExpired, country))); string response = TryGet(uri, timeout); List<Symbol> symbols = new List<Symbol>(255); List<Symbol> converted = JsonConvert.DeserializeObject<List<Symbol>>(response, new CountryCodeConverter()); if (converted != null) symbols = converted; return symbols; }
/// <summary> /// Private method which exposes all possible parameters, with default values for the optional ones. /// </summary> /// <param name="category">Category=StockOption, IndexOption, FutureOption or CurrencyOption</param> /// <param name="symbolRoot">Symbol root. Required Field, the symbol the option is a derivative of, this search will not return options based on a partial root.</param> /// <param name="strikeCount">Number of strikes prices above and below the underlying price. Defaults to 3. Ignored if strike price high and low are passed.</param> /// <param name="strikePriceLow">Strike price low</param> /// <param name="strikePriceHigh">Strike price high</param> /// <param name="dateCount">Number of expiration dates. Default value 3. Ignored if expiration dates high and low are passed.</param> /// <param name="expirationDateLow">Expiration date low</param> /// <param name="expirationDateHigh">Expiration date high</param> /// <param name="optionType">Option type (Both, Call, Put) Default: Both</param> /// <param name="futureType">Future type (Electronic, Pit) Default: Electronic</param> /// <param name="symbolType">SymbolType (Both, Composite, Regional) Default: Composite</param> /// <param name="country">Country code (US, DE, CA) Default: US</param> /// <returns></returns> public static string GetOptionSearchCriteria(SearchCategory category, string symbolRoot, uint strikeCount = 3, decimal strikePriceLow = 0, decimal strikePriceHigh = decimal.MaxValue, uint dateCount = 3, DateTime? expirationDateLow = null, DateTime? expirationDateHigh = null, OptionType optionType = OptionType.Both, FutureType futureType = FutureType.Electronic, SymbolType symbolType = SymbolType.Composite, CountryCode country = CountryCode.US) { if (string.IsNullOrEmpty(symbolRoot)) throw new ArgumentException("symbolRoot is required.", "symbolRoot"); if (GetAssetType(category) != AssetClass.Option) throw new ArgumentException("SearchCategory must be StockOption, IndexOption, FutureOption or CurrencyOption", "category"); if (strikePriceLow < 0) throw new ArgumentOutOfRangeException("strikePriceLow", "Argument cannot be less than 0."); if (strikePriceHigh < 0) throw new ArgumentOutOfRangeException("strikePriceHigh", "Argument cannot be less than 0."); if ((expirationDateLow.HasValue && !expirationDateHigh.HasValue) || (expirationDateHigh.HasValue && !expirationDateLow.HasValue)) throw new ArgumentException("If either expiration date parameter is passed, both must be passed."); if (expirationDateHigh.HasValue && expirationDateLow.HasValue && expirationDateHigh < expirationDateLow) throw new ArgumentOutOfRangeException("expirationDateHigh", "expirationDateHigh cannot be before expirationDateLow."); StringBuilder criteria = new StringBuilder(255); Append(criteria, "c=" + category.ToString()); Append(criteria, "R=" + symbolRoot); // strike price range takes precidence over strike count if (strikePriceLow > 0 && strikePriceHigh < decimal.MaxValue) { Append(criteria, "Spl=" + strikePriceLow); Append(criteria, "Sph=" + strikePriceHigh); } else if (strikeCount != 3) Append(criteria, "Stk=" + strikeCount); // daterange takes precidence over datacount if (expirationDateLow.HasValue) { Append(criteria, "Edl=" + ((DateTime)expirationDateLow).ToString("MM-dd-yyyy")); Append(criteria, "Edh=" + ((DateTime)expirationDateHigh).ToString("MM-dd-yyyy")); } else if (dateCount != 3) Append(criteria, "Exd=" + dateCount); if (optionType != OptionType.Both) Append(criteria, "OT=" + optionType.ToString()); if (futureType != FutureType.Electronic) Append(criteria, "FT=" + futureType.ToString()); if (symbolType != SymbolType.Composite) Append(criteria, "ST=" + symbolType.ToString()); if (country != CountryCode.US) Append(criteria, "Cnt=" + country.ToString()); return criteria.ToString(); }
public ContractDetail() { FutureType = FutureType.General; }
/// <summary> /// Private method which exposes all possible parameters, with default values for the optional ones. /// </summary> /// <param name="category">Category=StockOption, IndexOption, FutureOption or CurrencyOption</param> /// <param name="symbolRoot">Symbol root. Required Field, the symbol the option is a derivative of, this search will not return options based on a partial root.</param> /// <param name="strikeCount">Number of strikes prices above and below the underlying price. Defaults to 3. Ignored if strike price high and low are passed.</param> /// <param name="strikePriceLow">Strike price low</param> /// <param name="strikePriceHigh">Strike price high</param> /// <param name="dateCount">Number of expiration dates. Default value 3. Ignored if expiration dates high and low are passed.</param> /// <param name="expirationDateLow">Expiration date low</param> /// <param name="expirationDateHigh">Expiration date high</param> /// <param name="optionType">Option type (Both, Call, Put) Default: Both</param> /// <param name="futureType">Future type (Electronic, Pit) Default: Electronic</param> /// <param name="symbolType">SymbolType (Both, Composite, Regional) Default: Composite</param> /// <param name="country">Country code (US, DE, CA) Default: US</param> /// <param name="timeout"></param> /// <returns></returns> private List<Symbol> OptionSymbolSearch(SearchCategory category, string symbolRoot, uint strikeCount = 3, decimal strikePriceLow = 0, decimal strikePriceHigh = decimal.MaxValue, uint dateCount = 3, DateTime? expirationDateLow = null, DateTime? expirationDateHigh = null, OptionType optionType = OptionType.Both, FutureType futureType = FutureType.Electronic, SymbolType symbolType = SymbolType.Composite, CountryCode country = CountryCode.US, int timeout = TimeoutDefault) { //if (!IsAuthorized) throw new ClientAuthorizationException(); if (strikePriceLow > 0 && strikePriceHigh == decimal.MaxValue) throw new ArgumentException("If strikePriceLow is passed a value must also be passed for strikePriceHigh.", "strikePriceHigh"); if (expirationDateLow.HasValue || expirationDateHigh.HasValue) { if (!expirationDateLow.HasValue || !expirationDateHigh.HasValue) throw new ArgumentException("If a value is passed for expiration date high or low, the other value must also be passed."); if (expirationDateHigh <= expirationDateLow) throw new ArgumentOutOfRangeException("expirationDateHigh", "ExpirationHigh must be greater than ExpirationLow."); } Uri uri = new Uri(root, string.Format("/v2/data/symbols/search/{0}", SymbolSearch.GetOptionSearchCriteria(category, symbolRoot, strikeCount, strikePriceLow, strikePriceHigh, dateCount, expirationDateLow, expirationDateHigh, optionType, futureType, symbolType, country))); string response = TryGet(uri, timeout); List<Symbol> result = new List<Symbol>(255); List<Symbol> deserialized = JsonConvert.DeserializeObject<List<Symbol>>(response, new CountryCodeConverter()); if (deserialized != null) { result = deserialized; result.Sort(new OptionComparer()); } return result; }