D3Charts-行情图(已废弃,转到knowledge)

K线

蜡烛图

测试页面-分时

测试的时候,可以从我们的web官网,点击对应市场的类别进去,就可以看到web版本的行情图了。

分时请求类似这样:

https://d.10jqka.com.cn/v6/time/hs_300033/last.js

沪深

上证

http://m.10jqka.com.cn/stockpage/hs_600000

深证

http://m.10jqka.com.cn/stockpage/hs_002142

创业板

http://m.10jqka.com.cn/stockpage/hs_300033

科创板

https://m.10jqka.com.cn/stockpage/hs_688022

代码里面市场是写的hckcb,但是会重定向到hc。

这个市场是通过688开头来判断的。

港股

https://m.10jqka.com.cn/stockpage/hk_HK0700

注意:港股代码是4位的
数字的话,第一位是固定0,字母的话把0换成HK
比如:腾讯控股,我们客户端里面显示的代码是00700,而请求web行情数据时,要改为HK0700,比如:
https://d.10jqka.com.cn/v6/line/hk_HK0700/01/last360.js

美股

https://m.10jqka.com.cn/stockpage/usa_MOGU

画图流程

  • 配置数据请求的参数
  • 拼装数据请求的url
  • 发送数据请求
  • 解析和格式化数据
  • 绘图

程序分析

行情图其实是由几种基本图形叠加构成的,线条部分,普通的line即可,关键在于K线图的柱子,是通过hqbar这种类型来实现的,代码位于d3charts的src/chart/hqbar目录下。

画图比较简单,核心还是在于数据的获取,即datapool相关的程序。

数据获取-DataPool

文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|-- common
| |-- OthersHq.js // 成交明细、五档行情数据等
| |-- index.js

|-- fs
| |-- FsHistory.js
| |-- FsMoneyFlow.js // TODO:资金流向数据
| |-- FsToday.js // 处理当日分时数据,这个需要重点关注
| |-- index.js

|-- kline
| |-- KlineBase.js
| |-- KlineCommon.js
| |-- KlineLast.js
| |-- index.js

|-- configs.js
|-- DataPool.js
|-- DataProvider.js // 请求数据
|-- helper.js
|-- stockstatus.js // TODO
|-- StockType.js // 对不同市场(通过正则匹配股票代码前缀来区分市场)做了一些差异化的处理(比如x轴指定显示的坐标内容-fsXaxisShow)

可以从src/datapool/DataPool.js的register()方法开始阅读代码。

这里有做单例设置,所以多次调用D3Charts.getDataPool()是没关系的,不会重复生成实例。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// kline数据配置
var klinedata = {
type: 'klineLast',
code: 'hs_300033',
ma: [5, 10, 30],
lastDays: 360
};

var dp = D3Charts.getDataPool();
dp.setStatus({
// TODO:是否要替换url
enableFilterUrl: true
});

// 获得数据
var dataProvider = D3Charts.getDataPool().register(klinedata);
D3Charts.getDataPool().onAction(dataProvider, 'PROVIDER_UPDATE.myproject', function (d) {

if (d.fetchStatus.code !== '000') return;

// 成交量要不要转换为“手”,即是否需要除以100
var needConvertoShou = d.data.stockType.needConvertoShou;
// 保留的小数位数
var keepLen = d.data.stockType.keepLen;
var minValueSpan = 20;

// 数据
var kData = d.data.dataArray;

var testN = kData.length
// 阴影区域起始日期
var testMarkAreaDateStart = kData[testN - 30].t
// 阴影区域截止日期
var testMarkAreaDateEnd = kData[testN - 10].t

var testMarkAreaDateStart1 = kData[testN - 60].t
var testMarkAreaDateEnd1 = kData[testN - 50].t

var testMarkAreaDateStart2 = kData[testN - 45].t
var testMarkAreaDateEnd2 = kData[testN - 35].t
});

数据源配置

和我们之前取服务端行情数据很类似:

1
2
3
4
5
6
{
type: 'klineLast',
code: code,
ma: [5, 10, 30],
lastDays: 360
}

要特别注意src/datapool/DataProvider.js这个文件,默认的数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static defaultOption = {
code:'hs_300033',
// 获取方式
// fetchType: 'jqXhrWithoutCallback',
// 接口版本
version: dataVersion,
// 类型再细分
dType: 'common',
protocol: dataProtocol,
// 是否持续更新
isKeepingGet: false,
// 更新频率: 重复获取data的间隔时间(毫秒)
// 行情服务器更新频率是1min :20160405
intervalTime: 60000
}

会将默认配置和用户传入的配置进行合并,形成最终的数据请求配置。

DataProvider有一个缓存机制,会通过私有storage变量,缓存配置信息,详见enableClassManagement()这个函数。

特别注意:

请求行情数据,最终发出去的其实是一个.js的资源请求,而这个.js文件的url,是通过数据项id、请求的数据长度、周期等转换而成的。

具体转换规则详见DataProvider.js中的getDataId()这个方法。

更换url地址

1
DataPoolgetFilterUrl(url)方法

正常情况下是不需要应用方更换地址的,只有特殊需求场景才需要,比如港股要求必须展示延时15分钟的数据。

解析结果

因为数据类型有多种,因此在datapool目录下,有多个解析数据结果的文件,比如解析K线数据的,就是src/datapool/kline/KLineCommon.js.

这类解析文件,一般会包含如下功能:

1、定义数据请求的url规则urlFormatter

2、对接口返回的数据进行格式化,比如精度处理等

一些问题

hxc3是什么?

这是兼容IE低版本(IE7、8)的数据池

hxc3.dataPool = D3charts.dataPool 拥有相同的api

现在没必要用这个了,新版的已经集成了行情图了。

数据中的ioac分别代表什么?

可以查看这个文档

单个K线数据的结构类似这样(可以在KLineBase.js中查看注释):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
a: 8.93, // 最高价 max
c: 7.859999999999999, // 收盘价 close
i: 7.85, // 最低价 min
ma5: 7.86, // ma5 均价线
ma10: 7.86,
ma30: 7.86,
n: 9661747, // 成交量 volume
o: 8.32, // 开盘价 open
yc: 8.32, // 昨收价 yesterdayClose
np: 198423455, // 成交额 volumePrice
afn: 23434444, // 盘后成交量,仅 科创板市场有该值
s: "be", // k线颜色 be --> 下跌, up--> 上涨 eq -> 持平
t: "20091225", // 时间 time
'h': parseFloat(obj['1968584']), // 换手率
// 昨结价
// 只用于sj(上金所) 期货,gzqh三个市场
'yj': parseFloat(obj['66']),
// 昨收
// 父类 和历史数据merge的时候(mergeHistoryWithCurrent),会补全
'yc': '',
// 上涨 下跌 持平
// 获取 k线颜色
// 父类 和历史数据merge的时候(mergeHistoryWithCurrent),会补全
's': ''
}
all.js返回的price格式说明

http://d.10jqka.com.cn/v6/line/hs_300033/01/all.js

价格price的格式,是四个数字为一组,表示一天的价格信息;第一个数字是最低价,后面3个数字是相对最低价的涨跌值,注意后面3个数字不是直接的价格数值。

并且数值需要除以接口返回的priceFactor这个字段,才是真正的精度。

所以可以看到KlineCommon.js中的arrangeHistory()方法解析数据时,是这样的:

1
2
3
4
5
6
7
8
9
for (var k = 0; k < 4; k++) {
// 有最低价或者最低价为0:因为顺序是['i', 'o', 'a', 'c'],即低-开-高-收,所以这是计算后面三个价格
if (result[i].i || result[i].i == 0) {
result[i][priceName[k]]= price[4*i+k]/priceFactor + result[i].i;
}else{
// 第一个数据,即最低价
result[i][priceName[k]]= price[4*i+k]/priceFactor;
}
}

比如同花顺的历史数据,从2009.12.25开始,前面2个日期是这样的:

172,47,108,1,162,5,49,17

精度字段priceFactor是100,那么也就是2009.12.25的:

  • 最低价是172/100=1.72
  • 开盘价是1.72 + 47/100 = 2.19
  • 最高价是1.72 + 108/100 = 2.80
  • 收盘价是1.72 + 1/100 = 1.73
last.js返回的price格式说明

逻辑在KLineLast.js中,以分号分割每日数据,然后以逗号分割单日的数据项。

单日数据项每个下标对应的含义如下:

  • 0:日期
  • 1:开盘价
  • 2:最高价
  • 3:最低价
  • 4:收盘价
  • 5:成交量
  • 6:成交额
  • 7:换手率
  • 8:昨结价
  • 9:盘后成交量 目前只有科创板有该值
  • 10:盘后成交笔数 目前只有科创板有该值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
let isGetTotalFirstData = false;

if (totalKlineNum == 0 || !d.data) return rr;

let dataArr = d.data.split(';');

for (let i = 0; i < dataArr.length; i++) {
let oneDayArr = dataArr[i].split(',');
if (forceHistory && needPopDate && needPopDate == oneDayArr[0]) {
break;
}
result.push({
t: oneDayArr[0],
o: parseFloat(oneDayArr[1]),
a: parseFloat(oneDayArr[2]),
i: parseFloat(oneDayArr[3]),
c: parseFloat(oneDayArr[4]),
n: parseFloat(oneDayArr[5]),
np: parseFloat(oneDayArr[6]),
h: parseFloat(oneDayArr[7]),
s: undefined,
yc: undefined,
// sj, gzqh, qh 三个市场用昨结价计算涨跌幅,涨跌额
yj: typeof oneDayArr[8] !== 'undefined' && oneDayArr[8] !== '' ? parseFloat(oneDayArr[8]) : undefined,
an: parseFloat(oneDayArr[9]),
anp: parseFloat(oneDayArr[10])
});

result[i].s = getKLineStatus(result[i], result[i - 1]);
if(i === 0){
result[i].yc = result[i].o;
isGetTotalFirstData = (firstDate == result[i].t);
}else{
result[i].yc = result[i-1].c;
}
}

if(isGetTotalFirstData){
result[0].yc = parseFloat(issuePrice);
}
OtherHq的数据字段

位于OtherHq.js中,以注释形式进行了说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*+----------------+-----------------------------------------------+
| curP | 最新价 (常用于五档买卖中的现价) |
+----------------+-----------------------------------------------+
| curPStatus | 最新价状态 |
+----------------+-----------------------------------------------+
| dynamicSYL | 动态市盈率 |
+----------------+-----------------------------------------------+
| hqStatus | |
+----------------+-----------------------------------------------+
| hqStatusDetail | |
+----------------+-----------------------------------------------+
| isStop | 是否停牌 |
+----------------+-----------------------------------------------+
| keepLen | 推荐的价格精度 |
+----------------+-----------------------------------------------+
| maxP | 最大值 |
+----------------+-----------------------------------------------+
| maxPStatus | 最大值状态 |
+----------------+-----------------------------------------------+
| minP | 最小值 |
+----------------+-----------------------------------------------+
| minPStatus | 最小值状态 |
+----------------+-----------------------------------------------+
| n | 成交量 |
+----------------+-----------------------------------------------+
| name | 股票名称 |
+----------------+-----------------------------------------------+
| np | 成交额 |
+----------------+-----------------------------------------------+
| openP | 开盘价 |
+----------------+-----------------------------------------------+
| openPStatus | 开盘价状态 |
+----------------+-----------------------------------------------+
| rate | 涨跌幅 展示时后面需要带% |
+----------------+-----------------------------------------------+
| rateP | 涨跌额 |
+----------------+-----------------------------------------------+
| shortcode | 股票代码 |
+----------------+-----------------------------------------------+
| sjl | 市净率 展示时后面需要带% |
+----------------+-----------------------------------------------+
| staticSYL | 静态市盈率 |
+----------------+-----------------------------------------------+
| stockM | 流通市值 |
+----------------+-----------------------------------------------+
| totalM | 总市值 |
+----------------+-----------------------------------------------+
| turnRate | 换手率 (常用于k线数据) |
+----------------+-----------------------------------------------+
| yesterdayP | 昨收 (期货等市场用 昨结价格 |
+----------------+-----------------------------------------------+
| zf | 振幅 |
+----------------+-----------------------------------------------+*/
涨跌幅是如何计算的?

优先用昨结价,如果没有,采用昨收价:

1
2
3
4
5
var lastPrice = data.yc;
var lastPrice4Rate = data.yj || lastPrice
result.rate =
decimalRound(((curPrise - lastPrice4Rate) / lastPrice4Rate) * 100, 2) +
'%';;

作图

K线图有个官方的名字,叫做蜡烛图,因此这种形状我们命名为CandleSticks,作图逻辑位于src/shape/CandleSticks.js文件中。

蜡烛图的数据结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var candle = {
shape: {
data: pointsByColor[d],
bandWidth: bandwidth,
yStart: _y1Start,
percent: 1,
drawTemplate: hqbarType
},
style: {
stroke: '',
fill: ''
},
z2: 1,
// {string} 鼠标悬浮时在图形元素上时鼠标的样式是什么。同 CSS 的 cursor。
cursor: 'default'
}

绘制柱子,则是计算好坐标数据,然后通过canvas的moveTo、lineTo、rect等API实现作图。以普通蜡烛图为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function klinePrice(data, bandWidth, fixed, ctx) {
var x, adjust, temp1, temp2;
if (bandWidth <= 3) {
map(data, (d, i) => {
x = add_5(d[1].lineX, fixed);
temp1 = add_5(d[1].lineYTop, fixed);
temp2 = add_5(d[1].lineYBottom, fixed);
// 微调 如果线的距离不到2,用2补全
// @todo 用1补还是看不到点,所以改用2
adjust = Math.abs(temp1 - temp2) < 2 ? 2 : 0
ctx.moveTo(x, temp1 - adjust);
ctx.lineTo(x, temp2);
});
} else {
map(data, (d, i) => {
x = add_5(d[1].lineX, fixed);
// 微调 矩形高度不足1时,画一条横线替代
if (d[1].h < 1) {
ctx.moveTo(add_5(d[0], fixed), add_5(d[1].y, fixed));
ctx.lineTo(add_5(d[0] + bandWidth, fixed), add_5(d[1].y, fixed));
} else {
ctx.rect(add_5(d[0], fixed), add_5(d[1].y, fixed), bandWidth, d[1].h);
}

ctx.moveTo(x, add_5(d[1].lineYTop, fixed));
ctx.lineTo(x, add_5(d[1].y, fixed));
ctx.moveTo(x, add_5(d[1].y + d[1].h, fixed));
ctx.lineTo(x, add_5(d[1].lineYBottom, fixed));

// ctx.moveTo(x, add_5(d[1].lineYTop, fixed));
// ctx.lineTo(x, add_5(d[1].lineYBottom, fixed));

})
}
}

K线图的柱子数据的计算逻辑

在HqbarModel.js中,可以重点看下getDrawData(info)这个方法,将原始数据计算为绘图所需的几何数据。

其中柱子的高度是开盘价与收盘价之差的绝对值:

1
h: Math.abs(yScale(info.o) - yScale(info.c)),

数据池(datapool)

数据通过d.10jqka.com.cn域名获取,源头是行情服务器。

接口负责人:ZS、LKJ、LZQ

数据池文档(新版):里面有各个字段的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
a: 8.93  // 最高价 max
c: 7.859999999999999 // 收盘价 close
i: 7.85 // 最低价 min
ma5: 7.86 // ma5 均价线
ma10: 7.86
ma30: 7.86
n: 9661747 // 成交量 volume
o: 8.32 // 开盘价 open
yc: 8.32 // 昨收价 yesterdayClose
np: 198423455 // 成交额 volumePrice
afn: 23434444 // 盘后成交量,仅 科创板市场有该值
s: "be" // k线颜色 be --> 下跌, up--> 上涨 eq -> 持平
t: "20091225" // 时间 time



av: 69.722 // 均价 , 外汇等市场此内容为空
n: 9200 // 成交量
nowp: 69.7 // 现价
np: 641438 // 成交金额
t: "20180828 1500" // 时间
nowpPct: -0.008264462809917363, // 现价对比昨收价(转换成%的话,需要乘以100)
avPct: -0.007489669421487582 // 均价对比昨收价(转换成%的话,需要乘以100)

其他相关文档:

WEB行情文档汇总

实时行情数据接口

支持的市场列表

分时接口

K线接口

K线时间段接口

图形超出画图区域怎么办?

可以通过axis下的space进行配置:

space

一般如果是图上要标东西,东西超出当前绘图区域了,我们会用y轴的space,或者domainScale来调整。而不是通过修改grid的top来调整,因为修改grid的top,这个标记像是掉出去了,没有画面里面配的那么一体,效果会变成类似这样:

grid.top

阴影区域

通过markArea进行配置,在markArea[x].data中设置阴影区域的起止范围。

注意这个范围是由2个坐标点决定的,是一个方形区块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
markArea: [{
$axisIndex: [0, 1],
label: {
normal: {
show: true,
style: {
position: 'inside',
fontSize: 16
}
}
},
areaStyle: {
normal: {
fill: 'rgba(91,212,147,0.2)'
}
},
data: [{
points: [{
xValue: testMarkAreaDateStart,
y: 'top'
},
{
xValue: testMarkAreaDateEnd,
y: 'bottom'
}
]
}],
z: 1
},
{
$axisIndex: [0, 2],
label: {
normal: {
show: true,
style: {
position: 'inside',
fontSize: 16
}
}
},
areaStyle: {
normal: {
fill: 'rgba(91,212,147,0.2)'
}
},
data: [{
points: [{
xValue: testMarkAreaDateStart,
y: 'top'
},
{
xValue: testMarkAreaDateEnd,
y: 'bottom'
}
]
}],
z: 1
},
{
$axisIndex: [0, 3],
label: {
normal: {
show: true,
style: {
position: 'inside',
fontSize: 16
}
}
},
areaStyle: {
normal: {
fill: 'rgba(91,212,147,0.2)'
}
},
data: [{
points: [{
xValue: testMarkAreaDateStart,
y: 'top'
},
{
xValue: testMarkAreaDateEnd,
y: 'bottom'
}
]
}],
z: 1
},
],

如何在一个画布上画多个图形?

可以配置多个Y轴axis,给其设置不同的$gridIndex

注意显示多个图形时,grid也要对应的配置多个。

如何设置坐标轴上显示的tick?

通过axis[x].tickValues进行控制,注意:x轴和y轴的返回值似乎不一样

针对x轴:

1
2
3
4
5
6
7
8
9
10
11
12
13
tickValues: function (domain) {
var n = domain.length - 1;
if (n < 6) {
return [domain[0]];
} else if (n < minValueSpan) {
return [domain[0], domain[n]];
} else {
var split = n / 6;
return [domain[Math.round(n / 6)], domain[Math.round(n * 3 /
6)], domain[Math.round(n * 5 / 6)]
];
}
}

针对y轴,可以让该配置返回一个数组,数组有几个值,就显示几个tick:

1
2
3
4
5
6
7
8
tickValues: function (domain) {                            
var min = domain[0];
var max = domain[1];
var detar = max - min;
return [domain[0], detar / 4 + domain[0], detar * 2 / 4 + domain[0],
detar * 3 / 4 + domain[0], domain[1]
];
}

如何在K线上画tip?

参考这个示例:http://datav.iwencai.com/platform/chartconfig.html#chartId=258

通过添加markpoint来实现,大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
chart.setOption(option, false, {
'VIEW_DID_RENDER_AFTER_SET_OPTION': function () {
let tips = []
tips.push({
symbol: {
type: 'rect',
offset: [0, 0], // 偏移量,如果是最左边或者最右边,需要偏移
size: [50, 50], // 框的大小
style: {
normal: {
fill: "#FF0000",
stroke: "#000000"
},
}
},
xValue: '20190726',// 画到哪个X坐标上
y: 10,
valueIndex: 1,
// info: markData[i].mainIntention,
info: 'what info'
})

option.markPoint[0].data = tips
console.log('option', option);

chart.setOption(option)
}
});

如何在tip中自定义文字?

tip的位置如何自定义?

y是指图像中心距离画布顶端的距离

如果想控制tip的高度,可以设置yValue

这个值有两种处理方法,一种是在绘图之前,你先根据你拿来绘图的data去找一下这个数据线的对应值,然后用这个值设置yValue
另一种是在第一次绘图之后,再获取markpoint的index值,再去series里找对应的那根线的数据,然后再重置markpoint的位置
第二种需要重绘,性能不如第一种

如果画出来的markpoint位置不对,可以设置offset来调整。

如何控制markpoint的层级?

后画的在上层,遮住先画的。

K线柱子宽度如何自动变化?

这个逻辑在HqbarView.js中。

这是根据像素来判断的,当计算出来的单个柱子宽度的像素值小于等于3,就会自动画成一根线条;这估计是以前定的规范

因此当设置的一屏显示的数据较多时(比如90个交易日),在不同机型上看到的柱子宽度会不一致,可能苹果手机上就是正常的宽度(苹果分辨率高),Android手机上就是一根线。

markpoint的三角形怎么画的?

数据请求相关的问题

请求实现的原理

用的fetch-jsonp这个库:

https://github.com/mudenglong/fetch-jsonp

回调只是传递了一个名称过去,感觉是fetch-jsonp内部做了处理(KlineBase.js中):
1、创建这个回调函数
2、请求成功后,http返回的内容自动调用这个回调函数
3、这个回调函数将数据通过fetchSuccess()传递给数据处理逻辑:

1

如何设置自动请求数据的频率?

通过intervalTime这个配置项来设置:

1
2
3
4
5
6
7
8
9
var fsdata = {
type: 'fsToday',
code: code,
isKeepingGet: true,
// 间隔多久更新一次(推荐大于60秒,因为现在服务端缓存是1分钟)
intervalTime: 2000
};

var dataProvider = D3Charts.getDataPool().register(fsdata);

如何停止自动请求数据?

数据请求是通过DataProvider来执行的,因此调用其stopGetData()方法即可:

1
2
3
4
5
6
 // 获得数据
var dataProvider = D3Charts.getDataPool().register(fsdata);

setTimeout(() => {
dataProvider.stopGetData();
}, 10000);

注意:目前只能停止,不能重新开启;有必要的话,可以销毁重新创建数据池和图表。

为什么请求历史K线数据时,不同服务器返回的.all接口最后一个日期不一致?

因为历史数据的缓存频率极低(12个小时,估计是历史K线的访问请求很大,所以做了这个策略,因此历史请求中的当日数据即使返回了也是不能用的),因此允许最后一天的数据不实时,靠前端用.today.js接口的数据进行补全。

所以请求历史K线时,可以看到总共会发出2个请求:

http://d.10jqka.com.cn/v6/line/hs_300033/01/all.js

http://d.10jqka.com.cn/v6/line/hs_300033/01/defer/today.js

如何控制显示的K线数据的数量?

在数据请求完成后,对数据进行裁剪

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/ 获得数据
var dataProvider = D3Charts.getDataPool().register(klinedata);
D3Charts.getDataPool().onAction(
dataProvider,
"PROVIDER_UPDATE.myproject",
function (d) {
if (d.fetchStatus.code !== "000") return;

var needConvertoShou = d.data.stockType.needConvertoShou;
var keepLen = d.data.stockType.keepLen;
var minValueSpan = 20;

var kData = d.data.dataArray;
// 裁剪返回的数据
kData.splice(-1);
chart.setOption({
data: [
{
originData: kData,
},
],
});
}
);

url中指定取数范围

分时

分时图显示的时间范围是如何设置的?

目前分时显示多长时间段是由后端返回的数据控制的,是根据返回的结果中的dotsCount字段来确定X轴范围的,详见hqHelper.js:

1
2
3
4
var xData = [];
for (let i = 0; i < totalTimeNum; i++) {
xData.push('___' + i);
}

比如这个接口:http://d.10jqka.com.cn/v6/time/hs_300033/last.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"hs_300033": {
"name": "同花顺",
"open": 1,
"stop": 0,
"isTrading": 0,
// 也是交易时间,但是只在分时资金流向中用到了(type = 'fsMoneyFlow')
"rt": "0930-1130,1300-1500,1505-1530",
// 交易时间
"tradeTime": ["0930-1130", "1300-1500", "1505-1530"],
"pre": "79.48",
"date": "20221019",
"data": "0930,79.41,333522,79.410,4200;0931,79.50,2154939,79.504,27100......1529,78.37,23511,78.862,300.00;1530,78.37,23511,78.862,300.00",
// 分时一天交易结束总共点数
"dotsCount": 268,
"dates": ["20221019"],
"afterTradeTime": "1500",
"marketType": "HS_stock_gem"
}
}

这是中证300波动指数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"120_000803": {
"name": "300波动",
"open": 1,
"stop": 0,
"isTrading": 0,
"rt": "0930-1130,1300-1500",
"tradeTime": ["0900-1600"],
"pre": "6075.0680",
"date": "20221019",
"data": "0930,6065.9981,203461960,13.0258,15619862;0931,6072.1400,706629050,11.4459,63892886;......1459,6006.3511,0,14.3568,0;1500,6002.7955,718455000,14.3164,59834300",
"dotsCount": 421,
"dates": ["20221019"],
"afterTradeTime": "",
"marketType": ""
}
}

这个就是根据dotsCount来绘制的,因此x轴画出来感觉都快到晚上20点了:

000803

成交量

潜规则

不同市场,展示的分时图横坐标不一样

详见StockType.js中的配置。

不同市场对应的正则匹配规则,是根据这个wiki来设置的。

警告:我们把这个规则写死在了前端,感觉是有风险的;如果后面市场有变更,那么所有应用方都需要升级D3Charts的版本才行。

市场限制规则

详见hqHelper.js中的getLimitByMarket()方法,对市场做了一些限制,比如:

部分市场默认设置了不显示成交量

程序标记:名称:市场代码
Others_wh:外汇:97、98、99
Others_zq:债券:19、35
Others_pmetal:贵金属:41
Others_gqh:国外期货:217,、219

具体的标记和市场对应关系,可以查看StockType.js文件。

ZP任务交接

打包可以单独打hq的包,避免js太大。

分时图

五档盘口和成交明细,是我们单独请求了接口,通过回调传给了应用方,他们自己去画表格。

和普通折线图的区别,就是横坐标是固定的,及时现在只到10:30,也会画到15:00.

市场影响的因素包括(hqHelper、StockType):X轴展示的刻度,以及小数精度

可以控制台打印处理好的数据,看下结果。

数据格式:时间,加个,成交额,均价,成交量。

URL拼接规则有一个wiki进行说明,我们程序里面也封装好了。

K线图

形状是我们扩展了一个shape

未来展望

功能优化

1、调试工具:选择后,自动生成配置

2、实时性:我们前端绘图搞不搞得定?数据可以服务端接口优化,也可以我们从客户端获取。

3、异常监控

4、原生体验:RN

产品化:TradingView

我们要是能搞出来,也不错

通过组件化快速搭建一个tradingview!