问题

看到一些股票数据或者数字货币的市场交易深度数据, 不同的价位, 交易的数量不同. 因为买价和卖价精度问题, 这就导致了市场深度可以非常深, 如下图所示:

这是一个火币网数字货币市场交易深度的示例图, 在页面上能看到100个深度, 实际在Rest API请求数据的时候,返回的市场深度可以是150个. 当然, 有些官网也可以返回深度合并的数据. 所以我在遇到这个问题的时候, 走了一点弯路, 实现了这个小的算法问题.

需求

对于盘口数据,买单向下合并,卖单向上合并. 同时, 合并的时候就遇到了几个问题需要解决.

  1. 合并的精度问题
  2. 相同深度订单数量计算

算法

我找到了API文档中的ask,bid数据作为样本.

1
2
3
4
5
6
7
8
"bids": [
[3.7721, 344.86],// [price, quote volume]
[3.7709, 46.66]
],
"asks": [
[3.7745, 15.44],
[3.7746, 70.52]
]

在数据样本中, bids是一个二维数组, 第一列是该深度的价格, 第二列是该深度的订单数量.
首先解决第一个问题, 如何解决合并深度问题:
比如卖单

1
2
3
4
5
6
[3.1225, 7],
[3.1229, 1],
[3.1231, 3],
[3.1232, 5],
[3.1233, 2],
[3.1234, 1]

对于上面的数据, 合并最后一位价格精度, 那深度数据是如何呢? 应该是这样的:

1
2
[3.123, 8],
[3.124, 11]

如果合并最后两位呢? 应该如下:

1
[3.13, 19]

可以看到算法如下:

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
/**
* @param number: 价格
* @param precision: 精度
* @return: 向上合并后的价格
*/
public float getCeilByLastNumber(float number, int precision) {
// 精度小于0,直接返回, 不做精度计算
if (precision < 0) {
return number;
}
// 计算小数点后有几位
int numberLengthAfterPoint = 0;
// 临时变量
float tempNum = 0;
if (number > 0) {
// 这一步的目的是为了方式0.0015这种数, 会出现1.5E-3这种科学计数法
tempNum = number + 1;
} else {
// 同上
tempNum = number - 1;
}
// 获取number的字符串表达
String numStr = tempNum + "";
// 以小数点分割,第二个数组元素即小数点后的数字
String[] numStrArray = numStr.split("\\.");
// 得到小数点后数字的长度
numberLengthAfterPoint = numStrArray[1].length();
if (numberLengthAfterPoint >= precision) {
// 向上取数
return getCeilNumberWithPrecision(number, numberLengthAfterPoint - precision + 1);
} else {
return number;
}
}

public float getCeilNumberWithPrecision(float number, int precision) {
return (float) (Math.ceil(number * ((int) Math.pow(10, precision))) / (((int) Math.pow(10, precision)) * 1.0f));
}

同理, 对于向下合并也是类似的.