写给新人的说明: 从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中进行的,这个函数每个区块都被调用一次,但是不足一小时,就马上退出:

Reveal spoiler

image.png

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

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

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

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

Reveal spoiler

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还要做些调整呢,这个就留以后再说吧,因为我实在是写不动了。

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

相关链接

Sort:  

好專業,真的學"廢"了><

学废了🤣🤣🤣

上一篇文章我感觉我听懂了,也了解原因始末,为什么继续看了这一篇又觉得自己好像理解错了,于是又把上一篇和这一篇继续研究读了好几遍😄

O哥,辛苦了。感受到当见证人如此地不容易啊。

现在让我看这些函数,感觉头皮都发麻。

敬佩我O帅 😄

已学废!

历害👍崇拜
可我还是没有完全的学废哦
不过大概知道一点就ok了🙈

O哥辛苦了!🌹🌹🌹

感谢大佬分享!对于我这个新人来说,一头雾水,以后会多拜读大佬的文章,向大佬学习请教!