oflyhigh avatar

写给新人的说明: 从HIVE市场价到历史中间价

oflyhigh

Published: 01 Dec 2021 › Updated: 01 Dec 2021写给新人的说明: 从HIVE市场价到历史中间价

写给新人的说明: 从HIVE市场价到历史中间价

在之前的文章中,我提到一个median_history_price的东东,并且简单将其解释为“最近3.5日的HIVE价格中间值”,这让一些小伙伴一头雾水,这玩意到底是啥啊,咋计算得来的?

image.png
(图源 :pixabay)

这篇文章对这个问题做一些简要的介绍,揭秘从HIVE市场价到median_history_price的变化过程。

见证人喂价

HIVE市场价自不必多说,有很多交易所上线了HIVE,并且有USDT、BTC等交易对,通过交易所提供的API,我们就可以获得或者计算出当前时刻,HIVE在此交易所的价格。

而见证人们要做的事情之一,就是利用一些工具或者自己写些脚本获取HIVE价格,然后发布到HIVE区块链上,这个过程就叫做喂价。

以下就是我之前发布的一次喂价:
image.png

每个见证人都会去做这项工作,比如说TOP20见证人当前喂价:

image.png
(From: https://www.cutehive.com/witnesses.php)

你可能会问为啥喂价不一样呢?这个是很正常的,因为见证人们可能从不同交易所获取价格,并且发布的时间也不一致,HIVE的价格还有波动,喂价自然不一致了。

从喂价到喂价中间价

好了,见证人发布了一堆喂价,那么系统按谁发布的价格来计算呢?按最高价?按最低价?按平均值? 另外还有就是系统是不是实时计算呢?

首先说是否实时的问题,因为计算过程其实也蛮复杂的,如果每个区块都要算一次,那么会占用很多资源,所以系统每小时才去计算一次,计算间隔定义如下:

#define HIVE_BLOCKS_PER_HOUR (60*60/HIVE_BLOCK_INTERVAL)
#define HIVE_FEED_INTERVAL_BLOCKS (HIVE_BLOCKS_PER_HOUR)

计算是在database::update_median_feed中进行的,这个函数每个区块都被调用一次,但是不足一小时,就马上退出:

image.png

好,计算时机(周期)我们已经知道了,下面来看按谁发布的价格来计算。

其实简单来回答这个问题就是,按当前排队要出块的一组见证人提供的喂价来计算。HIVE有许多见证人,每轮21个见证人出块,TOP20+timeshare。

所以系统首先获取当前这轮见证人的喂价,大致操作是获取当前一轮见证人,然后逐个获取见证人喂价。分别用的是get_witness_schedule_object()以及get_witness

我们也可以用API获取上述两项信息,比如调用:database_api.get_witness_schedule,我们可以获取其中的current_shuffled_witnesses

image.png

然后用condenser_api.get_witnesses或者database_api.list_witnesses逐个遍历上述见证人,就可以获得它们的喂价信息了。

好了,现在我们有21组喂价信息了,这又该如何处理呢?按最高价?按最低价?按平均值? 答案是按中间值。也就是说讲获取的数值排序,取中间值。

取中间值的好处就是可以避免有不靠谱数据影响结果。假设取平均值,如果有一个值偏差200倍,那么平均值也会偏10倍以上,而中间值也不受影响。
核心代码如下:

std::sort( feeds.begin(), feeds.end() );
auto median_feed = feeds[feeds.size()/2];

喂价中间价以及历史中间价

好了,现在我们已经获取了见证人喂价的中间价,那么系统是不是直接使用这个数值呢?也不是,因为受价格波动影响,这个数据不够平滑。

所以这里又多了两个新概念,历史喂价以及历史喂价中间价

所谓历史喂价就是把见证人喂价中间价保存起来,形成一个列表。而这个列表有多长呢?答案是最近3.5天内的:

#define HIVE_FEED_HISTORY_WINDOW (12*7) // 3.5 days

之前我们说过,更新喂价的计算每小时调用一次,所以3.5天的历史喂价列表长度就是84每次更新把旧的数据踢出去,把新的数据插进来

我们也可以用database_api.get_feed_history来获取这个历史喂价列表:
image.png

上边列表一共有84个条目,限于篇幅,我只截图一部分。

有个这个列表后,我们在取中间值,就是我们最终要的结果啦。

std::vector< price > copy( fho.price_history.begin(), fho.price_history.end() );
std::sort( copy.begin(), copy.end() );
fho.current_median_history = copy[copy.size()/2];

其中current_median_history就是median_history_price啦,只是不同场合或者命令行钱包,或者API中命名略有区别,但是都是这个东西啦。

image.png
(图源 :pixabay)

所以,从市场价到median_history_price还是一个颇为复杂的过程,其实这只是正常情况,还有一种极端情况HBD占比超过10%,这个median_history_price还要做些调整呢,这个就留以后再说吧,因为我实在是写不动了。

就这样啦,小伙伴们学废了嘛?

相关链接

Leave 写给新人的说明: 从HIVE市场价到历史中间价 to:

Written by

Programmer, Maker, Freelancer, Witness. Make friends, Make money, Make life better!

Read more #hive-105017 posts


Best Posts From oflyhigh

We have not curated any of oflyhigh's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.

More Posts From oflyhigh