-
Notifications
You must be signed in to change notification settings - Fork 22
/
engine.go
135 lines (122 loc) · 4.55 KB
/
engine.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright (c) 2022 Gobalsky Labs Limited
//
// Use of this software is governed by the Business Source License included
// in the LICENSE.VEGA file and at https://www.mariadb.com/bsl11.
//
// Change Date: 18 months from the later of the date of the first publicly
// available Distribution of this version of the repository, and 25 June 2022.
//
// On the date above, in accordance with the Business Source License, use
// of this software will be governed by version 3 or later of the GNU General
// Public License.
package liquidity
import (
"context"
"sync"
"time"
"code.vegaprotocol.io/vega/core/types"
"code.vegaprotocol.io/vega/libs/num"
)
//go:generate go run github.com/golang/mock/mockgen -destination mocks/auction_state_mock.go -package mocks code.vegaprotocol.io/vega/core/monitor/liquidity AuctionState
type AuctionState interface {
IsOpeningAuction() bool
IsLiquidityAuction() bool
IsLiquidityExtension() bool
StartLiquidityAuction(t time.Time, d *types.AuctionDuration)
SetReadyToLeave()
InAuction() bool
ExtendAuctionLiquidity(delta types.AuctionDuration)
ExpiresAt() *time.Time
}
// TargetStakeCalculator interface
//
//go:generate go run github.com/golang/mock/mockgen -destination mocks/target_stake_calculator_mock.go -package mocks code.vegaprotocol.io/vega/core/monitor/liquidity TargetStakeCalculator
type TargetStakeCalculator interface {
GetTheoreticalTargetStake(rf types.RiskFactor, now time.Time, markPrice *num.Uint, trades []*types.Trade) *num.Uint
}
type Engine struct {
mu *sync.Mutex
params *types.LiquidityMonitoringParameters
minDuration time.Duration
tsCalc TargetStakeCalculator
}
func NewMonitor(tsCalc TargetStakeCalculator, params *types.LiquidityMonitoringParameters) *Engine {
e := &Engine{
mu: &sync.Mutex{},
tsCalc: tsCalc,
}
e.UpdateParameters(params)
if e.minDuration < 1 {
e.minDuration = time.Second
}
return e
}
func (e *Engine) UpdateParameters(params *types.LiquidityMonitoringParameters) {
// temp hard-coded duration of 1 until we can make these parameters required
if params.AuctionExtension == 0 {
params.AuctionExtension = 1
}
e.params = params
}
func (e *Engine) SetMinDuration(d time.Duration) {
e.mu.Lock()
e.minDuration = d
e.mu.Unlock()
}
func (e *Engine) UpdateTargetStakeTriggerRatio(ctx context.Context, ratio num.Decimal) {
e.mu.Lock()
e.params.TriggeringRatio = ratio
// @TODO emit event
e.mu.Unlock()
}
// CheckLiquidity Starts or Ends a Liquidity auction given the current and target stakes along with best static bid and ask volumes.
// The constant c1 represents the netparam `MarketLiquidityTargetStakeTriggeringRatio`,
// "true" gets returned if non-persistent order should be rejected.
func (e *Engine) CheckLiquidity(as AuctionState, t time.Time, currentStake *num.Uint, trades []*types.Trade,
rf types.RiskFactor, refPrice *num.Uint, bestStaticBidVolume, bestStaticAskVolume uint64, persistent bool,
) bool {
exp := as.ExpiresAt()
if exp != nil && exp.After(t) {
// we're in auction, and the auction isn't expiring yet, so we don't have to do anything yet
return false
}
e.mu.Lock()
c1 := e.params.TriggeringRatio
md := int64(e.minDuration / time.Second)
e.mu.Unlock()
targetStake := e.tsCalc.GetTheoreticalTargetStake(rf, t, refPrice.Clone(), trades)
ext := types.AuctionDuration{
Duration: e.params.AuctionExtension,
}
// if we're in liquidity auction already, the auction has expired, and we can end/extend the auction
// @TODO we don't have the ability to support volume limited auctions yet
isOpening := as.IsOpeningAuction()
if exp != nil && as.IsLiquidityAuction() || as.IsLiquidityExtension() || isOpening {
if currentStake.GTE(targetStake) && bestStaticBidVolume > 0 && bestStaticAskVolume > 0 {
as.SetReadyToLeave()
return false // all done
}
// we're still in trouble, extend the auction
as.ExtendAuctionLiquidity(ext)
return false
}
// multiply target stake by triggering ratio
scaledTargetStakeDec := targetStake.ToDecimal().Mul(c1)
scaledTargetStake, _ := num.UintFromDecimal(scaledTargetStakeDec)
stakeUndersupplied := currentStake.LT(scaledTargetStake)
if stakeUndersupplied || bestStaticBidVolume == 0 || bestStaticAskVolume == 0 {
if stakeUndersupplied && len(trades) > 0 && !persistent {
// non-persistent order cannot trigger auction by raising target stake
// we're going to stay in continuous trading
return true
}
if exp != nil {
as.ExtendAuctionLiquidity(ext)
return false
}
as.StartLiquidityAuction(t, &types.AuctionDuration{
Duration: md, // we multiply this by a second later on
})
}
return false
}