Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
 // 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;
     }
 }
Ejemplo n.º 3
0
        // 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);
            }
        }
Ejemplo n.º 4
0
        /// <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());
        }
Ejemplo n.º 5
0
        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());
        }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 7
0
        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();
        }
Ejemplo n.º 8
0
        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);
        }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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
        }
Ejemplo n.º 11
0
        /// <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
        }
Ejemplo n.º 12
0
        /*
         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);
        }
Ejemplo n.º 13
0
        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);
        }
Ejemplo n.º 14
0
        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;
        }
Ejemplo n.º 15
0
        /// <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();
        }
Ejemplo n.º 16
0
 public ContractDetail()
 {
     FutureType = FutureType.General;
 }
Ejemplo n.º 17
0
        /// <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;
        }