Я использую Alpha Vantage API для получения ежедневной информации об акциях. Я действительно новичок в использовании API и не знаю, что я делаю неправильно

Поэтому я использую C# xamarin и создаю базовое приложение для акций, которое может получать котировки акций с помощью API Alpha Vantage. У меня есть то, что я думал, может сработать, но это не работает вообще. Да, это школьный проект, поэтому я не ожидаю, что люди просто сделают это. Цель этого приложения состоит в том, чтобы использовать API, и мне нужно показать данные, которые оно предоставляет после того, как пользователь вводит символ акции с первой страницы приложения. Мне нужно отправить этот символ с API, и я не уверен, что я вытягиваю объект JSON, и я не знаю, как добраться до каждого поля в объекте, когда я получаю JSON правильно. Этот код - то, что я пытаюсь и Я не получаю никакой информации, заполненной ни в одном из моих текстовых представлений.

namespace Stock_Quote
{
    [Activity(Label = "StockInfoActivity1")]
    public class StockInfoActivity1 : Activity
    {
        private ISharedPreferences prefs = Application.Context.GetSharedPreferences("APP_DATA", FileCreationMode.Private);
        TextView txtSymbol, txtOpen, txtClose, txtHigh, txtLow, txtVolume;
        string webservice_url = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=";

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            // Create your application here
            SetContentView(Resource.Layout.activity_stock_info);
            txtSymbol = FindViewById<TextView>(Resource.Id.txtSymbol);
            txtOpen = FindViewById<TextView>(Resource.Id.txtOpen);
            txtClose = FindViewById<TextView>(Resource.Id.txtClose);
            txtHigh = FindViewById<TextView>(Resource.Id.txtHigh);
            txtLow = FindViewById<TextView>(Resource.Id.txtLow);
            txtVolume = FindViewById<TextView>(Resource.Id.txtVolume);
            string current = prefs.GetString("current", "no stok symbol found");

            //txtSymbol.Text = current;

            try
            {
                webservice_url = webservice_url + current + "&apikey=AVALIDAPIKEY";
                Uri url = new Uri(webservice_url);
                var webRequest = WebRequest.Create(url);

                if (webRequest != null)
                {

                    webRequest.Method = "GET";
                    webRequest.ContentType = "application/json";

                    //Get the response 
                    WebResponse wr = webRequest.GetResponseAsync().Result;
                    Stream receiveStream = wr.GetResponseStream();
                    StreamReader reader = new StreamReader(receiveStream);

                    Stock currentStockInfo = JsonConvert.DeserializeObject<Stock>(reader.ReadToEnd());

                    if (currentStockInfo.RestResponse.result == null)
                    {
                        txtSymbol.Text = "No stock found";
                    }
                    else
                    {                        
                        txtSymbol.Text = current;
                        txtOpen.Text = currentStockInfo.RestResponse.stockInfo.Open;
                        txtClose.Text = currentStockInfo.RestResponse.stockInfo.Close;
                        txtHigh.Text = currentStockInfo.RestResponse.stockInfo.High;
                        txtLow.Text = currentStockInfo.RestResponse.stockInfo.Low;
                        txtVolume.Text = currentStockInfo.RestResponse.stockInfo.Volume;
                    }


                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
    }
    public class Result
    {
        public string Information { get; set; }
        public string Symbol { get; set; }
        public string Last { get; set; }
        public string Size { get; set; }
        public string TimeZone { get; set; }
    }

    public class StockInfo
    {
        public string Open { get; set; }
        public string High { get; set; }
        public string Low { get; set; }
        public string Close { get; set; }
        public string Volume { get; set; }
    }

    public class RestResponse
    {       
        public Result result { get; set; }
        public StockInfo stockInfo { get; set; }
    }

    public class Stock
    {
        public RestResponse RestResponse { get; set; }
    }
}

3 ответа

Решение

JSON, возвращаемый из этой конечной точки, не совсем соответствует вашей модели.

Вот строка, где вы говорите своей программе, как анализировать ответ:

Stock currentStockInfo = JsonConvert.DeserializeObject (reader.ReadToEnd ());

... но ответ выглядит так:

{
    "Meta Data": {
        "1. Information": "Daily Prices (open, high, low, close) and Volumes",
        "2. Symbol": "MSFT",
        "3. Last Refreshed": "2018-12-10 16:00:02",
        "4. Output Size": "Compact",
        "5. Time Zone": "US/Eastern"
    },
    "Time Series (Daily)": {
        "2018-12-10": {
            "1. open": "104.8000",
            "2. high": "107.9800",
            "3. low": "103.8900",
            "4. close": "107.5900",
            "5. volume": "39050766"
        },
        "2018-12-07": {
            "1. open": "108.3800",
            "2. high": "109.4500",
            "3. low": "104.3000",
            "4. close": "104.8200",
            "5. volume": "45044937"
        }...
    ...
    ...
    ...

}

Вы пытаетесь превратить весь этот ответ в один Stock объект, который не собирается работать. Ответ не является Stock, это ответ с 2 объектами, один из которых имеет много Stock объекты.

Вы можете попытаться создать модель для этого *, но я бы рекомендовал превратить весь этот ответ в JObject (еще один объект в NewtonSoft JSON.Net).

Вот DotNetFiddle, который я собрал, чтобы продемонстрировать, как он работает.

https://dotnetfiddle.net/Iz8UsD

Дайте мне знать, если я могу добавить что-нибудь более полезное.

РЕДАКТИРОВАТЬ: * Вы можете, вероятно, заставить строго типизированную модель работать здесь, проблема в том, что каждый Stock имеет другое имя JSON. Я не знаю, как заставить синтаксический анализатор анализировать каждый как Stock сохраняя при этом данные. Я буду играть с этим сегодня вечером.

Проблема, как объяснил Джо, заключается в том, что форма возвращаемого JSON не позволяет легко сопоставить объект C#.

Вот более простой / быстрый способ получения цен на акции из AlphaVantage с помощью C#.

Он включает вызов стандартной конечной точки цены API, но с добавлением "&datatype=csv" в качестве параметра URL. Формат ответа позволяет легко сопоставить объект C# Poco. В приведенном ниже примере я просто сопоставляю его с объектом AlphaVantageData.

Пример кода ниже. Вы можете запустить этот код прямо в Gystlin здесь

using System;
using System.Collections.Generic;
using System.Linq;
using ServiceStack;
using ServiceStack.Text;

public class AlphaVantageData
{
     public DateTime Timestamp { get; set; }
     public decimal Open { get; set; }

     public decimal High { get; set; }
     public decimal Low { get; set; }

     public decimal Close { get; set; }
     public decimal Volume { get; set; }
}

 // retrieve monthly prices for Microsoft
 var symbol = "MSFT";
 var monthlyPrices = $"https://www.alphavantage.co/query?function=TIME_SERIES_MONTHLY&symbol={symbol}&apikey=demo&datatype=csv"
            .GetStringFromUrl().FromCsv<List<AlphaVantageData>>();

 monthlyPrices.PrintDump();

 // some simple stats
 var maxPrice = monthlyPrices.Max(u => u.Close);
 var minPrice = monthlyPrices.Min(u => u.Close);

Я публикую этот ответ, потому что у меня есть рабочий код, который анализирует временные ряды AlphaVantage (ежедневно) в список котировок акций. Затем он сравнивает котировки в поисках опорных точек. Эта часть нуждается в доработке, но список правильно загружается из ежедневной ленты.

      using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;

namespace StockQuotes
{
    public class Program
    {
        static void Main(string[] args)
        {

            List<string> quoteTickerSymbols = new List<string>();

            if (args.Length < 1)
            { quoteTickerSymbols.Add("msft"); }
            else
            {
                string[] data = args[0].Split(',');
                quoteTickerSymbols.Add(data.ToString());
            }

            //please use your own API key.
            string APIKey = "";
            string response = "";
            string nameOfStock = "";
            HttpClient client = new HttpClient();
            StringBuilder sb = new StringBuilder();
            List<StockQuote> quotes = new List<StockQuote>();

            for (int i = 0; i < quoteTickerSymbols.Count;)
            {
                sb.Append($"https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=");
                sb.Append(quoteTickerSymbols[i]);
                sb.Append("&apikey=");
                sb.Append(APIKey);

                string request = sb.ToString();

                response = client.GetStringAsync(request).Result;
                JObject jsonData = JObject.Parse(response);

                nameOfStock = quoteTickerSymbols[i];
                try
                {
                    foreach (JToken item in jsonData.SelectTokens("['Time Series (Daily)']"))
                    {
                        foreach (var datedCollection in item.Children().Children())
                        {
                            sb.Clear();
                            string[] pathArray = datedCollection.Path.Split('.');

                            // the date that's after the Time Series (Daily) part of the path
                            sb.Append(pathArray[1]);

                            DataSetByDay dataSet = datedCollection.ToObject<DataSetByDay>();

                            var quote = datedCollection.Select(x => new StockQuote()
                            {
                                Name = nameOfStock,
                                date = Convert.ToDateTime(sb.ToString()),
                                open = dataSet.open,
                                high = dataSet.high,
                                low = dataSet.low,
                                close = dataSet.close,
                                volume = dataSet.volume
                            });

                            quotes.Add(quote.First());
                            dataSet = null;
                        }
                    }
                }
                catch (Exception err)
                {

                    // write out the issue and then skip the entry.
                    Console.WriteLine(err.Message, err.InnerException, err.Source);
                    i++;
                }

                // move to next token
                i++;

                // at the end, compare the quotes.
                for (int j = 0; j < quotes.Count() - 4; j++)
                {
                    if (quotes[j].open > quotes[j + 1].high && quotes[j].close < quotes[j + 1].low)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("{0}", quotes[j].Name);
                        Console.WriteLine("Pivot downside {0}", quotes[j].date);
                    }
                    if (quotes[j].open < quotes[j + 1].low && quotes[j].close > quotes[j + 1].high)
                    {
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine("{0}", quotes[j].Name);
                        Console.WriteLine("Pivot upside {0}", quotes[j].date);
                    }
                }
            }
        }
    }
}

это тоже нужно. Для хранения информации.

      using Newtonsoft.Json;
using System;

namespace StockQuotes
{
    // each daily record from the website
    internal class DataSetByDay
    {
        [JsonProperty("1. open")]
        public decimal open { get; set; }

        [JsonProperty("2. high")]
        public decimal high { get; set; }

        [JsonProperty("3. low")]
        public decimal low { get; set; }

        [JsonProperty("4. close")]
        public decimal close { get; set; }
        [JsonProperty("5. volume")]
        public long volume { get; set; }
    }

    //this would append the date and the name of the stock to the time series.
    internal class StockQuote : DataSetByDay
    {
       public string Name { get; set; }
        public DateTime date { get; set; }
    }
}
Другие вопросы по тегам