Dynamic Pricing for Bulk Coretime Sales

This post proposes a dynamic pricing mechanism based on a power function. The function is constructed so the price stays fairly stable around a governance-controlled target number of cores sold in the previous period, and scales down to a minimum price or maximum price increase factor as it deviates from the target.

Gavin Wood’s proposal

RFC-1, currently live as a pull request here, proposes the sale of bulk coretime on a 4-weekly basis.

According to RFC-1, pricing should be dynamic and change every sale period based on the price and demand of the previous period. RFC-1 defines the mechanism to set the price as out of the scope of the proposal.

RFC-1 notes:

Notes on Price Setting

The specific price setting mechanism is out of scope for this proposal and should be covered in some other work. The present proposal assumes the existence of a price-setting mechanism which could take into account three parameters; two mostly fixed and one which changes each BULK_PERIOD. These parameters are BULK_TARGET, BULK_LIMIT and CORES_SOLD which is the actual number of cores sold for the present BULK_PERIOD and is always an unsigned integer at most BULK_LIMIT.

In general we would expect the price to increase the closer CORES_SOLD gets to BULK_LIMIT and to decrease the closer it gets to zero. If it is exactly equal to BULK_TARGET, then we would expect the price to remain the same.

A simple example of this would be the formula:

NEW_PRICE := IF CORES_SOLD < BULK_TARGET THEN
   OLD_PRICE - OLD_PRICE / 2 * CORES_SOLD / BULK_TARGET
ELSE
   OLD_PRICE + OLD_PRICE / 2 *
       (CORES_SOLD - BULK_TARGET) / (BULK_LIMIT - BULK_TARGET)
END IF

This exists only as a trivial example to demonstrate a basic solution exists, and should not be intended as a concrete proposal.

The intended function looks like this:

Design Goals

Starting from the function given above, the following improvements are proposed:

  • Left side goes to zero
  • Price plateaus around the target
  • Introduce a max price increase factor

Details

Left side goes to zero

The left side of the function only goes to OLD_PRICE / 2. In conditions of rapid price changes on the market, this might lead to a period of one or a few months where the price does not adapt quickly enough to changing markets. It is proposed to allow the left side of the function to go close to 0 if cores sold go to 0. The rationale is that if there are actually 0 cores sold, something about the previous sale price was fundamentally wrong and the price needs to adapt quickly.

We introduce MIN_PRICE as a new variable.

Price plateaus around BULK_TARGET

If the number of cores is close to BULK_TARGET, less extreme price changes might be sensible. This ensures that a drop in sold cores or an increase doesn’t lead to immediate price changes, but rather slowly adapts. Only if more extreme changes in the number of sold cores occur, does the price slope increase.

We introduce SCALE_DOWN and SCALE_UP to control for the steepness of the left and the right side of the function respectively.

Introduce a max price increase factor

Introducing this lever gives governance an additional control lever and avoids the necessity for a future runtime upgrade.

We introduce MAX_PRICE_INCREASE_FACTOR as a factor of what the price may increase from one period to another.

Function

Parameters

We assume these parameters from RFC-1:

  • BULK_LIMIT - the maximum number of cores being sold
  • BULK_TARGET - the target number of cores being sold
  • CORES_SOLD - the number of cores being sold
  • OLD_PRICE - the price of a core in the previous period

And additionally, introduce:

  • MIN_PRICE - the minimum price a core will always cost. MIN_PRICE >= 0
  • MAX_PRICE_INCREASE_FACTOR - the factor by which the price maximally can change from one period to another. MAX_PRICE_INCREASE_FACTOR > 1
  • SCALE_DOWN - the steepness of the left side of the function. Should be >= 1
  • SCALE_UP - the steepness of the right side of the function. Should be >= 1

CODE

in Python

    if CORES_SOLD <= BULK_TARGET:
        return (OLD_PRICE - MIN_PRICE) * (1 - (abs(CORES_SOLD - BULK_TARGET)**SCALE_DOWN / BULK_TARGET**SCALE_DOWN)) + MIN_PRICE
    else:
        return ((MAX_PRICE_INCREASE_FACTOR - 1) * OLD_PRICE * ((CORES_SOLD - BULK_TARGET)**SCALE_UP / (BULK_LIMIT - BULK_TARGET)**SCALE_UP)) + OLD_PRICE

Examples

Basic Proposal

This example proposes that the minimum price of a core is 1 DOT, the price can grow a maximum of 50% every 4 weeks and we want to dampen price change around BULK_TARGET slightly.

BULK_TARGET = 30
BULK_LIMIT = 45
MIN_PRICE = 1
MAX_PRICE_INCREASE_FACTOR = 2
SCALE_DOWN = 2
SCALE_UP = 2
old_price = 1000

We get

More aggressive pricing

We might want to have a more aggressive price growth, allowing the price to double every 4 weeks and have a linear increase in price if more than BULK_TARGET cores are sold.

BULK_TARGET = 30
BULK_LIMIT = 45
MIN_PRICE = 1
MAX_PRICE_INCREASE_FACTOR = 2
SCALE_DOWN = 2
SCALE_UP = 1
old_price = 1000

Conservative pricing to ensure quick corrections in a bull market

If governance considers the risk that a sudden surge in DOT price might price chains out from bulk coretime markets, it can ensure the model quickly reacts to a quick drop in demand, by setting 0 < SCALE_DOWN < 1 and setting the max price increase factor more conservatively.

BULK_TARGET = 30
BULK_LIMIT = 45
MIN_PRICE = 1
MAX_PRICE_INCREASE_FACTOR = 1.5
SCALE_DOWN = 0.5
SCALE_UP = 2
old_price = 1000

Linear pricing

By setting the scaling factors to 1 and potentially adapting the max price increase, we can achieve a linear function.

BULK_TARGET = 30
BULK_LIMIT = 45
MIN_PRICE = 1
MAX_PRICE_INCREASE_FACTOR = 1.5
SCALE_DOWN = 1
SCALE_UP = 1
OLD_PRICE = 1000

Code

A Jupyter Notebook is shared here: Google Colab

A Gist backup of the notebook is found here: Dynamic Coretime Pricing · GitHub

Future Work

I hacked together the function with my fellow pair programmer GPT-4. It’s quite possible that the mathematically inclined will find it to be confusing in its construction. I’m open to any criticism.

If this function finds acceptance, it should be tested if it is still working for different parameter sets.

This function may become part of an RFC to accompany the realization of RFC-1

Conclusion

This proposal introduces a flexible function for dynamic coretime pricing that gives governance intuitive control levers and comes close to the proposal in RFC-1 while providing more fine-grained control of the shape of the price curve.

5 Likes

@gavofyork I think this idea is very interesting to research & learn more deeply

2 Likes

This is now RFC-6