https://steemit.com/bitshares/@clockwork/bitshares-smart-coins-and-the-pricefeed
As most of you know, the BitShares DEX gives users the ability to create smart-coins (MPAs, market pegged assets).
These are special assets that are not issued at will but can only be "borrowed" into existence from the blockchain by tying up a certain amount of collateral in a backing asset.
The most classic example is bitUSD which tracks the value of 1 USD and is always backed by collateral in BTS of at least 1.75x its value. (so 1 bitUSD is backed by at least 1.75$ worth of BTS).
The specifics behind MPAs, the need for their existence and the ways of trading them have been heavily discussed and there is a wealth of information out there just a google search away.
As the existence of MPAs depends on a fair price, this price is provided by the pricefeed for that MPA which is published to the blockchain at regular intervals, usually by the BitShares witnesses.
As a BitShares witness and seeing as I recently started work on porting @xeroc's pricefeed script (https://github.com/xeroc/bitshares-pricefeed/) to Javascript for mine and community use, as well as continued maintenance, this article will deal with the pricefeed and how it is derived.
To start of, this is what a pricefeed publish operation looks like (commented for clarity)
{
"asset_id": "1.3.121",
// The asset we're providing a price for. In this case bitUSD
"extensions": [],
"fee": {
"amount": 57,
// The fee for the publish_feed operation...
// ...in BTS
"asset_id": "1.3.0"
},
"feed": {
"core_exchange_rate": {
// The Core Exchange Rate for the asset (used when paying fees with bitUSD)
"base": {
"amount": 11930000,
// Amount of 'sats' (lowest divisible value) ...
// ... of bitUSD...
"asset_id": "1.3.121"
},
// ...that are required to buy...
"quote": {
"amount": 553300000,
// ... amount of 'sats' (lowest divisible value) ...
// ...of BTS.
"asset_id": "1.3.0"
}
},
"maintenance_collateral_ratio": 1750,
"maximum_short_squeeze_ratio": 1100,
// The current settlement price for the asset
"settlement_price": {
"base": {
"amount": 16050000,
"asset_id": "1.3.121"
},
"quote": {
"amount": 781600000,
"asset_id": "1.3.0"
}
}
},
"publisher": "1.2.711128"
// The account of the witness publishing this feed.
}
Maintainance collateral ratio & max short squeeze ratio are related to the margin mechanics and are better explained here: http://docs.bitshares.org/bitshares/user/dex-margin-mechanics.html.
In essence, the pricefeed provides 2 prices for the MPA:
a) A Core Exchange Rate which is used with the fee pool to pay fees with the MPA rather than BTS.
This is 5% higher than the settlement price (20% in the case of bitCNY) and the reason is to avoid Fee Pool Draining:
If an order is created and paid in a non-BTS asset, the fee is implicitly exchange into BTS to pay the network fee. However, if the order is canceled, 90% of the fee will be returned as BTS. The result is, that if the core exchange rate is lower than the highest bid, people can simply buy your token from the market, and exchange them implicitly with the fee pool by creating and canceling an order. This will deplete the fee pool and leave the issuer with his tokens at a slight loss (depending on the offset of the core exchange rate). For this reason, we recommend to use a core exchange that is slightly higher than the market price of your asset. As a consequence, paying fees in BTS should always be cheaper.
b) The settlement price which is what most of you know as the feed price.
You may wonder why those prices are published in this format and not as a simple 0.20 USD/BTS.
The reason is that MPAs have multiple feeds provided by witnesses and the chain calculates the median value at any given time to use as the de facto feed price. Seeing as we are in a decentralised environment that requires consensus, all nodes must reach the same conclusion as to what the median feed price is. Due to floating point non-deteminism (see: https://randomascii.wordpress.com/2013/07/16/floating-point-determinism/), doing those calculations on different machines, running possibly different versions of bitshares-core, compiled with different compiler and library versions etc. means that consensus is not guaranteed unless we use integers.
The correct way to read the settlement price above is as follows:
16050000 of the lowest denomination of bitUSD (which has precision 4) so
16050000 x 0.0001 = 1605USD
will get you
781600000 of the lowest denomination of BTS (which has precision 5) so
781600000 x 0.00001 = 7816BTS
Leading to a price of: 1605/7816 = 0.2053 USD/BTS
(The trailing zeroes are a side-effect of the calculations in @xeroc's pricefeed script which is something I have optimised in the Javascript port)
But how are those prices calculated?
This is up to each individual witness, the sources they use and how they configure their pricefeed script.
For example, to calculate the BTS/USD price, a witness could pull BTS/BTC prices from Binance, AEX, Poloniex and Huobi along with their trade volumes and get a volume-weighted average BTS/BTC price.
They could then do the same for BTC/USD using data from say GDAX,Kraken,Bitfinex etc. to get a volume weighted BTC/USD price.
The BTS/USD price then would be the product of BTS/BTC and BTC/USD.
Both @xeroc's pricefeed script and the Javascript port I've worked on allow the witness to create a configuration file that essentially states a list of sources and the asset pair prices that should be gathered from each one.
Once a full list of asset pairs are available, you can configure a list of intermediate assets to point out how those pairs can be combined to get a final price (in the example above, BTC would have to be listed as an intermediate asset) and whether an asset is allowed to have its price derived from 3 or 2 markets.
For example, allowing bitEUR to be derived from 3 markets, with BTC and USD listed as intermediate assets, means that a potential price for BitEUR/BTS could be reached via BTS/BTC , BTC/USD and the USD/EUR forex rate. This price would then be averaged together with all the other possible combinations for bitEUR/BTS that the script could reach.
Adding a new source to the script is as simple as creating a new Class for that source that implements/extends the FeedSource class. (See here: https://github.com/clockworkgr/bitshares-pricefeed-js/blob/master/sources/FeedSource.js and an example for Binance here: https://github.com/clockworkgr/bitshares-pricefeed-js/blob/master/sources/Binance.js)
Assuming the witness has picked his sources, configuration and averaging mechanism, he ends up with a final fair price for the MPA.
Say for example: 0.205624768946542 USD/BTS.
Since bitUSD uses precision 4, we can round this to 0.2056USD/BTS.
Using the logic we explained earlier, we multiply both the numerator and denominator by 10 to the precision of the numerator & denominator asset accordingly.
We now have 2056 'sats' of bitUSD for 100000 'sats' of BTS.
so the correct way of publishing that price would be:
"settlement_price": {
"base": {
"amount": 2056,
"asset_id": "1.3.121"
},
"quote": {
"amount": 100000,
"asset_id": "1.3.0"
}
}
One of the other optimisations I implemented in the Javascript port, is to run those numbers through a GCD calculation first. In this case the GCD is 8, leading to a final price feed of:
"settlement_price": {
"base": {
"amount": 257,
"asset_id": "1.3.121"
},
"quote": {
"amount": 12500,
"asset_id": "1.3.0"
}
}
I know this was a little bit more technical, but I hope it clears a few things up with regards to pricefeeds in BitShares
My Javascript pricefeed script is still under development and testing and can be found here: https://github.com/clockworkgr/bitshares-pricefeed-js