-
Notifications
You must be signed in to change notification settings - Fork 0
/
types.go
98 lines (79 loc) · 2.59 KB
/
types.go
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package simulation
import (
"math/rand"
"sort"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// PriceGenerator allows deterministic price generation in simulations
type PriceGenerator struct {
markets []string
currentPrice map[string]sdk.Dec
maxPrice map[string]sdk.Dec
minPrice map[string]sdk.Dec
increment map[string]sdk.Dec
currentBlockHeight int64
}
// NewPriceGenerator returns a new market price generator from starting values
func NewPriceGenerator(startingPrice map[string]sdk.Dec) *PriceGenerator {
p := &PriceGenerator{
markets: []string{},
currentPrice: startingPrice,
maxPrice: map[string]sdk.Dec{},
minPrice: map[string]sdk.Dec{},
increment: map[string]sdk.Dec{},
currentBlockHeight: 0,
}
divisor := sdk.MustNewDecFromStr("20")
for marketID, startPrice := range startingPrice {
p.markets = append(p.markets, marketID)
// allow 10x price increase
p.maxPrice[marketID] = sdk.MustNewDecFromStr("10.0").Mul(startPrice)
// allow 100x price decrease
p.minPrice[marketID] = sdk.MustNewDecFromStr("0.01").Mul(startPrice)
// set increment - should we use a random increment?
p.increment[marketID] = startPrice.Quo(divisor)
}
// market prices must be calculated in a deterministic order
// this sort order defines the the order we update each market
// price in the step function
sort.Strings(p.markets)
return p
}
// Step walks prices to a current block height from the previously called height
// noop if called more than once for the same height
func (p *PriceGenerator) Step(r *rand.Rand, blockHeight int64) {
if p.currentBlockHeight == blockHeight {
// step already called for blockHeight
return
}
if p.currentBlockHeight > blockHeight {
// step is called with a previous blockHeight
panic("step out of order")
}
for _, marketID := range p.markets {
lastPrice := p.currentPrice[marketID]
minPrice := p.minPrice[marketID]
maxPrice := p.maxPrice[marketID]
increment := p.increment[marketID]
lastHeight := p.currentBlockHeight
for lastHeight < blockHeight {
upDown := r.Intn(2)
if upDown == 0 {
lastPrice = sdk.MinDec(lastPrice.Add(increment), maxPrice)
} else {
lastPrice = sdk.MaxDec(lastPrice.Sub(increment), minPrice)
}
lastHeight++
}
p.currentPrice[marketID] = lastPrice
}
p.currentBlockHeight = blockHeight
}
// GetCurrentPrice returns price for last blockHeight set by Step
func (p *PriceGenerator) GetCurrentPrice(marketID string) sdk.Dec {
price, ok := p.currentPrice[marketID]
if !ok {
panic("unknown market")
}
return price
}