使用 ASP.NET Core MVC 和 RESTful API 创建股票图表






4.25/5 (7投票s)
本文演示了如何在 Web 应用程序中使用 ASP.NET Core MVC 和 RESTful API 创建跨平台股票图表。
引言
.NET Core 的主要优势之一是它可以在多个平台和架构上运行。因此,您可以在一个平台上构建应用程序,然后在 Windows、Linux、MacOS 以及 x86 和 ARM 等不同架构上运行它。在本文中,我将演示如何使用 ASP.NET Core (2.0) MVC 和 RESTful API 创建一个跨平台股票图表应用程序。
ASP.NET Core 中的 API 控制器与常规控制器类似,只是它们的动作方法生成的响应是数据对象,这些对象在没有 HTML 标记的情况下发送到客户端。从应用程序传递数据的最常见方法是使用 REST 模式。RESTful Web API 的核心前提是拥抱 HTTP 的特性,以便请求方法指定服务器要执行的操作,而请求 URL 指定要应用该操作的一个或多个数据对象。
接下来,我将使用 ASP.NET Core MVC、RESTful API 和 Google Charts 来创建一个股票图表应用程序。ASP.NET Core MVC 提供了创建跨平台 Web 应用程序的基础,RESTful API 控制器提供了对服务器上数据的访问,而 Google Charts API 提供了一个图表库,允许我们在客户端渲染股票图表。
使用 API 控制器访问股票数据
首先,打开 Visual Studio 2017,从一个名为 NetCoreStockChart
的新 ASP.NET Core (2.0) MVC 项目开始。向该项目添加一个名为 YahooFinanceApi
的新 NuGet 包。该包将用于从 Yahoo Finance 检索历史(每日、每周和每月)股票数据。
在 Models 文件夹中添加一个名为 StockPriceModel
的新类。以下是该类的代码
namespace NetCoreStockChart.Models
{
public class StockPriceModel
{
public string Ticker { get; set; }
public string Date { get; set; }
public decimal Open { get; set; }
public decimal High { get; set; }
public decimal Low { get; set; }
public decimal Close { get; set; }
public decimal AdjustedClose { get; set; }
public decimal Volume { get; set; }
}
}
现在,在 Controllers 文件夹中添加一个名为 ApiStockDataController
的 API 控制器,并用以下代码替换其内容
using Microsoft.AspNetCore.Mvc;
using NetCoreStockChart.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using YahooFinanceApi;
namespace NetCoreStockChart.Controllers
{
[Produces("application/json")]
public class ApiStockDataController : Controller
{
[Route("~/api/ApiStockData/{ticker}/{start}/{end}/{period}")]
[HttpGet]
public async Task<List<StockPriceModel>> GetStockData(string ticker, string start,
string end, string period)
{
var p = Period.Daily;
if (period.ToLower() == "weekly") p = Period.Weekly;
else if (period.ToLower() == "monthly") p = Period.Monthly;
var startDate = DateTime.Parse(start);
var endDate = DateTime.Parse(end);
var hist = await Yahoo.GetHistoricalAsync(ticker, startDate, endDate, p);
List<StockPriceModel> models = new List<StockPriceModel>();
foreach (var r in hist)
{
models.Add(new StockPriceModel
{
Ticker = ticker,
Date = r.DateTime.ToString("yyyy-MM-dd"),
Open = r.Open,
High = r.High,
Low = r.Low,
Close = r.Close,
AdjustedClose = r.AdjustedClose,
Volume = r.Volume
});
}
return models;
}
}
}
此 API 控制器允许您访问历史(每日、每周或每月)股票数据。现在,运行此项目,在浏览器的地址栏中输入以下 URL
https://:63930/api/apistockdata/ibm/2018-01-01/2018-02-01/daily
然后按 Enter 键,您将获得 IBM 的 EOD(当日收盘)股票数据,如图 1 所示。
当然,您也可以使用常规控制器来访问股票数据。但是,这种方法在速度、效率和开放性方面存在严重不足。
创建股票图表
在本节中,我们将使用 Google Charts API 和 API 控制器中的股票数据来创建股票图表。
将以下名为 StockChart
的方法添加到 HomeController
public IActionResult StockChart()
{
return View();
}
右键单击此方法,然后选择“添加视图…”——这将向项目中添加一个名为 StockChart.cshtml 的视图。用以下代码替换其内容
<div id="div" class="row" style="padding:20px;">
<div class="col-md-3">
<div class="row form-group form-inline" style="margin-top:5px">
<label class="col-sm-5 control-label" for="ticker">Ticker:</label>
<div class="col-sm-7">
<input id="ticker" type="text" class="form-control input-sm"
style="height:25px;width:100%" value="SPY" />
</div>
</div>
<div class="row form-group form-inline" style="margin-top:-5px">
<label class="col-sm-5 control-label" for="startDate">Start Date:</label>
<div class="col-sm-7">
<input id="startDate" type="text" class="form-control input-sm"
style="height:25px;width:100%" value="2016-01-01" />
</div>
</div>
<div class="row form-group form-inline" style="margin-top:-5px">
<label class="col-sm-5 control-label" for="endDate">End Date:</label>
<div class="col-sm-7">
<input id="endDate" type="text" class="form-control input-sm"
style="height:25px;width:100%" value="2018-01-01" />
</div>
</div>
<div class="row form-group form-inline" style="margin-top:20px">
<div class="col-sm-5"></div>
<div class="col-sm-7">
<button id="btnCreateChart" class="btn btn-primary">Create Chart</button>
</div>
</div>
</div>
<div class="col-md-9">
<div id="chart" style="width:100%;height:700px;overflow:hidden;padding:10px">
<div id="candlestick" style="height:55%"></div>
<div id="volume" style="height:30%;margin-top:-1%"></div>
<div id="filter" style="height:15%;margin-top:1%"></div>
</div>
</div>
</div>
@section scripts{
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script>
createStockChart();
$('#btnCreateChart').click(function () {
createStockChart();
});
function createStockChart() {
google.charts.load('current', { 'packages': ['corechart', 'controls'] });
google.charts.setOnLoadCallback(drawChart);
var chart_div = document.getElementById('chart');
var ticker = document.getElementById('ticker').value;
var startDate = document.getElementById('startDate').value;
var endDate = document.getElementById('endDate').value;
var viewStartDate = (new Date(endDate));
viewStartDate.setMonth(viewStartDate.getMonth() - 3);
var viewEndDate = new Date(endDate);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('datetime', 'Date');
data.addColumn('number', 'Open');
data.addColumn('number', 'High');
data.addColumn('number', 'Low');
data.addColumn('number', 'Close');
data.addColumn('number', 'Volume');
$.ajax({
url: '/api/apiStockData/' + ticker + '/' + startDate + '/' + endDate + '/daily',
method: 'GET',
dataType: 'json'
}).done(function (d) {
d.forEach(function (di) {
data.addRow([{ v: new Date(di.date), f: di.date }, di.open,
di.high, di.low, di.close, di.volume]);
});
var dashboard = new google.visualization.Dashboard(chart_div);
var control = new google.visualization.ControlWrapper({
controlType: 'ChartRangeFilter',
containerId: 'filter',
options: {
filterColumnIndex: 0,
ui: {
chartType: 'LineChart',
chartOptions: {
chartArea: {
height: '80%', width: '85%', left: 100,
backgroundColor: { stroke: "gray", strokeWidth: 1 }
},
hAxis: { baselineColor: 'none' }
},
chartView: { columns: [0, 4] },
}
},
state: {
range: {
start: viewStartDate,
end: viewEndDate
}
}
});
var chart = new google.visualization.ChartWrapper({
chartType: 'CandlestickChart',
containerId: 'candlestick',
options: {
chartArea: { height: '80%', width: '85%', left: 100,
backgroundColor: { stroke: "gray", strokeWidth: 1 } },
hAxis: { type: 'category', slantedText: false, maxTextLines: 1,
maxAlternation: 1 },
legend: { position: 'none' },
candlestick: {
fallingColor: { strokeWidth: 0, fill: '#a52714' },
risingColor: { strokeWidth: 0, fill: '#0f9d58' }
},
title: 'Stock Price: ' + ticker,
},
view: { columns: [0, 3, 1, 4, 2] }
});
var volume = new google.visualization.ChartWrapper({
chartType: 'ColumnChart',
containerId: 'volume',
options: {
chartArea: { height: '80%', width: '85%', left: 100, top: 40, bottom: 30,
backgroundColor: { stroke: "gray", strokeWidth: 1 } },
hAxis: { type: 'category', slantedText: false, maxTextLines: 1,
maxAlternation: 1 },
legend: { position: 'none' },
title: "Volume: " + ticker
},
view: { columns: [0, 5] }
});
dashboard.bind(control, [chart, volume]);
dashboard.draw(data);
}).fail(function () {
alert('Failed to create the chart. Please try it again.');
});
}
}
</script>
}
该代码首先使用 google.chart.load
方法加载 corechart
API 的当前版本,并实现一个名为 drawChart
的函数。请特别注意我们如何使用 Ajax 访问由 RESTful API 控制器在服务器上创建的股票数据,以及我们如何逐行将股票数据添加到 DataTable
中。
接下来,我们将使用 Google Charts API 将多个图表组合成一个仪表板,并提供 ChartRangeFilter
控件来操作它们显示的数据。仪表板接收一个包含要可视化的数据的 DataTable
,并负责绘制数据并将其分发给仪表板的所有图表。在我们的示例中,仪表板包含三个部分:ChartRangeFilter
控件、一个蜡烛图和一个成交量图。
运行此项目并单击顶部主菜单中的**股票图表**,将生成 SPY 的默认股票图表,如图 2 所示。
现在,您可以在 Ticker 字段中输入任何有效的美国股票代码,并对时间段进行任何更改,最后单击“创建图表”按钮来创建股票图表。
例如,在 Ticker 字段中输入 IBM,并在 Start Date 和 End Date 字段中分别输入 2010-01-01 和 2015-05-31。现在单击“创建图表”按钮,将为 IBM 创建一个股票图表,如图 3 所示。
从图 2 和图 3 中可以看到,图表分为三个部分:顶部是股票价格(开盘价、最高价、最低价和收盘价)的蜡烛图;中间是成交量图;底部是用于选择图表中显示的数据范围的范围选择控件。范围选择控件由一个带有两个滑块的滑块组成,它显示整个数据集的视图,并提供用于放大和缩小数据部分的工具以及在数据集之间平移的功能。