股票shares后端
网址链接
使用新浪股票接口来接收股票信息绘制日K
String rs= UrlContent.getContent(
"http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?" +
"symbol=sz000001&schttp://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?symbol=sz002095&scale=60&ma=no&datalen=400http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?symbol=sz002095&scale=60&ma=no&datalen=400ale=60&ma=no&datalen=400",
"gbk");
return rs;
package com.fjr.shares.util;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
public class UrlContent {
public static String getContent(String path, String charset) {
InputStream in = null;
StringBuilder result = new StringBuilder();
try {
URL url = new URL(path);
URLConnection uc = url.openConnection();
in = uc.getInputStream();// 获取读入流
InputStream raw = new BufferedInputStream(in);// 放入缓冲流
Reader r = new InputStreamReader(raw,charset); // 用Reader接收
BufferedReader br= new BufferedReader(r); //这样便于可以按行读
String s = br.readLine();
while(s!= null) {
result.append(s);
s = br.readLine();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result.toString();
}
}
股票接口
Sina股票实时数据接口
以大秦铁路(股票代码:601006)为例,如果要获取它的最新行情,只需访问新浪的股票数据接口:
http://hq.sinajs.cn/list=sh601006
这个url会返回一串文本,例如:
var hq_str_sh601006=“大秦铁路, 27.55, 27.25, 26.91, 27.55, 26.20,26.91, 26.92,
22114263, 589824680, 4695, 26.91, 57590, 26.90, 14700, 26.89,14300,
26.88, 15100, 26.87, 3100, 26.92, 8900, 26.93, 14230, 26.94, 25150,26.95, 15220, 26.96, 2008-01-11, 15:05:32”;
这个字符串由许多数据拼接在一起,不同含义的数据用逗号隔开了,按照程序员的思路,顺序号从0开始。
0:”大秦铁路”,股票名字;
1:”27.55″,今日开盘价;
2:”27.25″,昨日收盘价;
3:”26.91″,当前价格;
4:”27.55″,今日最高价;
5:”26.20″,今日最低价;
6:”26.91″,竞买价,即“买一”报价;
7:”26.92″,竞卖价,即“卖一”报价;
8:”22114263″,成交的股票数,由于股票交易以一百股为基本单位,所以在使用时,通常把该值除以一百;
9:”589824680″,成交金额,单位为“元”,为了一目了然,通常以“万元”为成交金额的单位,所以通常把该值除以一万;
10:”4695″,“买一”申请4695股,即47手;
11:”26.91″,“买一”报价;
12:”57590″,“买二”
13:”26.90″,“买二”
14:”14700″,“买三”
15:”26.89″,“买三”
16:”14300″,“买四”
17:”26.88″,“买四”
18:”15100″,“买五”
19:”26.87″,“买五”
20:”3100″,“卖一”申报3100股,即31手;
21:”26.92″,“卖一”报价
(22, 23), (24, 25), (26,27), (28, 29)分别为“卖二”至“卖四的情况”
30:”2008-01-11″,日期;
31:”15:05:32″,时间;
历史数据接口
http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?symbol=sz002095&scale=60&ma=no&datalen=400
获取深圳市场002095股票的以60分钟为间隔的数据,获取了最近的1023个节点。(但是目前通过实验发现,只能获取到最多488条记录)
参数说明:
参数写法 说明
symbol=[市场][股票代码] sz深市、sh沪市
scale=[周期] 单位是分钟,
由于A股每天交易4小时,共240分钟。若scale=30,则每天的数据是8条,若scale=60,则每天数据4条。
必须是5的倍数。
ma=no 是否需要取向前的加权平均值(分别是5分钟、10分钟、30分钟的数据)
datalen=[长度] 如果只获取最近的一条数据,则datalen=1
返回结果说明:
day日期和时间、open开盘价、high最高价、low最低价、close收盘价、volume成交量;向前复权的数据。
返回结果示例:
请求:
http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?symbol=sz002095&scale=60&ma=no&datalen=10
结果:
[
{“day”:“2020-07-30 11:30:00”,“open”:“20.650”,“high”:“20.660”,“low”:“20.510”,“close”:“20.590”,“volume”:“426501”},
{“day”:“2020-07-30 14:00:00”,“open”:“20.590”,“high”:“20.600”,“low”:“20.480”,“close”:“20.550”,“volume”:“460330”},
{“day”:“2020-07-30 15:00:00”,“open”:“20.550”,“high”:“20.550”,“low”:“20.340”,“close”:“20.370”,“volume”:“750885”},
{“day”:“2020-07-31 10:30:00”,“open”:“20.490”,“high”:“20.740”,“low”:“20.350”,“close”:“20.620”,“volume”:“1225035”},
{“day”:“2020-07-31 11:30:00”,“open”:“20.620”,“high”:“20.650”,“low”:“20.400”,“close”:“20.450”,“volume”:“584424”},
{“day”:“2020-07-31 14:00:00”,“open”:“20.470”,“high”:“20.600”,“low”:“20.450”,“close”:“20.550”,“volume”:“298512”},
{“day”:“2020-07-31 15:00:00”,“open”:“20.550”,“high”:“20.650”,“low”:“20.500”,“close”:“20.630”,“volume”:“878311”},
{“day”:“2020-08-03 10:30:00”,“open”:“20.900”,“high”:“21.030”,“low”:“20.710”,“close”:“20.840”,“volume”:“1285384”},
{“day”:“2020-08-03 11:30:00”,“open”:“20.840”,“high”:“21.270”,“low”:“20.820”,“close”:“21.040”,“volume”:“1501880”},
{“day”:“2020-08-03 14:00:00”,“open”:“21.060”,“high”:“21.120”,“low”:“20.980”,“close”:“21.080”,“volume”:“269644”}
]
跨域配置
因为前端访问需要跨域,后端需要进行跨域配置
package com.fjr.shares.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CrossConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")/*所有的当前站点的请求地址,都支持跨域访问*/
.allowedOriginPatterns("*")/*所有的外部域都可跨域访问*/
.allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")/*哪些请求 需要跨域配置*/
.allowCredentials(true) /*是否支持跨域用户凭证*/
.maxAge(300)/*超时时长设置为5分钟。 时间单位是秒。*/
.allowedHeaders("*");/*请求体的头部*/
}
}
股票前端
vue的搭建
-
项目初始化(搭建环境略)
-
在当前目录下输入“vue init webpack项目名称(使用英文)”
vue init webpack mytest -
注意几项选NO[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M8OtS8gb-1639205681872)(C:\Users\sixteenccc\AppData\Roaming\Typora\typora-user-images\image-20211211130116718.png)]
-
成功如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lZNFGt3s-1639205681873)(C:\Users\sixteenccc\AppData\Roaming\Typora\typora-user-images\image-20211211130139127.png)]
cnpm install xxxx来下载项目中用到的依赖
-
股票数据处理
npm下载echars,在main.js引入echars,详情见官网
import * as echarts from 'echarts'//引入echarts Vue.prototype.$echarts = echarts //引入组件
可能会出现的问题:
vue导入echars问题:可能会造成init初始化问题,检查版本以及下述操作
a) 导入依赖:cnpm install echarts -S
b) 在main.js中引入
import * as echarts from 'echarts'
// 注意:这里要 * as echarts 而不是 import echarts from xxx
和Vue.prototype.$echarts = echarts
c) div设置宽高,使用ref调用,将document.getElementById(‘myChart’)换成$refs(不然会造成 Error Initialize failed invalid dom错误)
绘制日K图
访问网址得到数据类型为
echars的K线图需要的数据类型为
对传回的数据进行处理
initData(data,day,open,high,low,close) {
let barValue = [];
data.forEach(item => {
let outValue = [];
outValue[0]= item.day;
outValue[1] = item.open;
outValue[2]= item.close;
outValue[3] = item.low;
outValue[4] = item.high;
barValue.push(outValue);
});
this.valueBar = barValue;
return barValue
},
进行画图
drawSharesUrl(){
var mythis = this;
//在ajax方法里写$(this)指向的是最近调用它的jquery对象,所以这里的$(this)指的是ajax对象,而不是DOM对象
console.log(rs)
if(rs.data==1){
axios({
method: 'get',
dataTypr:'json',
url: 'http://localhost:8080/user/sz000001',//访问后端接口,得到数据
}).then(function(rs) {
console.log(rs.data);
let myChart = mythis.$echarts.init(mythis.$refs.xxx);
//需要提供一个div 给他宽高框框才可以画图,
const upColor = '#ec0000';
const upBorderColor = '#8A0000';
const downColor = '#00da3c';
const downBorderColor = '#008F28';
// Each item: open,close,lowest,highest
//对传来的数据进行格式处理,参考
const data0 = splitData(mythis.initData(rs.data, 'day','open','high','low','close'));
//除了data其他可以照抄官网的数据处理initData()方法
function splitData(rawData) {
const categoryData = [];
const values = [];
for (var i = 0; i < rawData.length; i++) {
categoryData.push(rawData[i].splice(0, 1)[0]);
values.push(rawData[i]);
}
return {
categoryData: categoryData,
values: values
};
}
function calculateMA(dayCount) {
var result = [];
for (var i = 0, len = data0.values.length; i < len; i++) {
if (i < dayCount) {
result.push('-');
continue;
}
var sum = 0;
for (var j = 0; j < dayCount; j++) {
sum += +data0.values[i - j][1];
}
result.push(sum / dayCount);
}
return result;
}
myChart.setOption({//这里需要使用myChart.setOption(option);
title: {
text: '平安银行(sz000001)',
left: 0
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
legend: {
data: ['日K', 'MA5', 'MA10', 'MA20', 'MA30']
},
grid: {
left: '10%',
right: '10%',
bottom: '15%'
},
xAxis: {
type: 'category',
data: data0.categoryData,
scale: true,
boundaryGap: false,
axisLine: { onZero: false },
splitLine: { show: false },
min: 'dataMin',
max: 'dataMax'
},
yAxis: {
scale: true,
splitArea: {
show: true
}
},
dataZoom: [
{
type: 'inside',
start: 50,
end: 100
},
{
show: true,
type: 'slider',
top: '90%',
start: 50,
end: 100
}
],
series: [
{
name: '日K',
type: 'candlestick',
data: data0.values,
itemStyle: {
color: upColor,
color0: downColor,
borderColor: upBorderColor,
borderColor0: downBorderColor
},
markPoint: {
label: {
formatter: function (param) {
return param != null ? Math.round(param.value) + '' : '';
}
},
data: [
{
name: 'Mark',
coord: ['2013/5/31', 2300],
value: 2300,
itemStyle: {
color: 'rgb(41,60,85)'
}
},
{
name: 'highest value',
type: 'max',
valueDim: 'highest'
},
{
name: 'lowest value',
type: 'min',
valueDim: 'lowest'
},
{
name: 'average value on close',
type: 'average',
valueDim: 'close'
}
],
tooltip: {
formatter: function (param) {
return param.name + '<br>' + (param.data.coord || '');
}
}
},
markLine: {
symbol: ['none', 'none'],
data: [
[
{
name: 'from lowest to highest',
type: 'min',
valueDim: 'lowest',
symbol: 'circle',
symbolSize: 10,
label: {
show: false
},
emphasis: {
label: {
show: false
}
}
},
{
type: 'max',
valueDim: 'highest',
symbol: 'circle',
symbolSize: 10,
label: {
show: false
},
emphasis: {
label: {
show: false
}
}
}
],
{
name: 'min line on close',
type: 'min',
valueDim: 'close'
},
{
name: 'max line on close',
type: 'max',
valueDim: 'close'
}
]
}
},
{
name: 'MA5',
type: 'line',
data: calculateMA(5),
smooth: true,
lineStyle: {
opacity: 0.5
}
},
{
name: 'MA10',
type: 'line',
data: calculateMA(10),
smooth: true,
lineStyle: {
opacity: 0.5
}
},
{
name: 'MA20',
type: 'line',
data: calculateMA(20),
smooth: true,
lineStyle: {
opacity: 0.5
}
},
{
name: 'MA30',
type: 'line',
data: calculateMA(30),
smooth: true,
lineStyle: {
opacity: 0.5
}
}
]
});
})
}
绘制如图
使用ecStat插件完成线性回归
安装ecStat详见官网
//使用的是腾讯股票接口绘制散点图进行线性回归穿线。X值为自然数,Y值为每分钟单价
var mdata=[]
$(document).ready(function() {
var myChart = echarts.init(document.getElementById('main'));
var option;
var mythis = this;
$.ajax({
url: "http://data.gtimg.cn/flashdata/hushen/minute/sz000001.js?maxage=110&0.28163905744440854",
dataType: "script",
cache: "false",
type: "GET",
success: function() {
//进行数据处理,腾讯返回的是一堆字符串而不是json
var msg = min_data;
var result = msg.replace(/\n/g, ",").split(',')
var arr = result.slice(2, result.length - 1), //开头结尾各一个空数组要去掉
_arr = [];
for (var i = 0; i < arr.length; i++) {
var _a = arr[i].split(" "),
_b = arr[i].split(" "),
_c = [];
if (i > 0) {
_c = arr[i - 1].split(" ");
}
// 腾讯股票接口传的数值0930(日期) 5.55(成交价) 37673(累计成交量,初始成交量为9:30的)
// 因此每分钟的 成交量 = 当前累计成交量 - 前一分钟的累计成交量
_b[2] = _c.length > 0 ? _a[2] - _c[2] : _a[2];
_arr.push(_b)
}
mdata = _arr
const barPrice=[]
for(var i=0;i<50;i++){
var price=[]
price.push(i)
price.push(Number(mdata[i][1]))
// console.log("price="+price)
barPrice[i]=price
}
//数据格式为下:
// const data=[
// [1, 3.176513],
// console.log(data)
// See https://github.com/ecomfe/echarts-stat
echarts.registerTransform(ecStat.transform.regression);
option = {
dataset: [{
source: barPrice
},
{
transform: {
type: 'ecStat:regression'
// 'linear' by default.
// config: { method: 'linear', formulaOn: 'end'}
}
}
],
title: {
text: '平安银行(价格线性回归图)',
left: 'center'
},
legend: {
bottom: 5
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
xAxis: {
splitLine: {
lineStyle: {
type: 'dashed'
}
}
},
yAxis: {
splitLine: {
lineStyle: {
type: 'dashed'
}
}
},
series: [{
name: 'scatter',
type: 'scatter'
},
{
name: 'line',
type: 'line',
datasetIndex: 1,
symbolSize: 0.1,
symbol: 'circle',
label: {
show: true,
fontSize: 16
},
labelLayout: {
dx: -20
},
encode: {
label: 2,
tooltip: 1
}
}
]
};
myChart.setOption(option);
}
})
})
绘制如图
symbolSize: 0.1,
symbol: 'circle',
label: {
show: true,
fontSize: 16
},
labelLayout: {
dx: -20
},
encode: {
label: 2,
tooltip: 1
}
}
]
};
myChart.setOption(option);
}
})
})
**绘制如图**
