Я использую 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; }
}
}