mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-23 15:25:14 +00:00
add price risk control
This commit is contained in:
parent
2058ce808b
commit
53309616c3
40
pkg/risk/riskcontrol/price.go
Normal file
40
pkg/risk/riskcontrol/price.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package riskcontrol
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
type PriceRiskControl struct {
|
||||
referencePrice *indicatorv2.EWMAStream
|
||||
lossThreshold fixedpoint.Value
|
||||
}
|
||||
|
||||
func NewPriceRiskControl(refPrice *indicatorv2.EWMAStream, threshold fixedpoint.Value) *PriceRiskControl {
|
||||
return &PriceRiskControl{
|
||||
referencePrice: refPrice,
|
||||
lossThreshold: threshold,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *PriceRiskControl) IsSafe(side types.SideType, price fixedpoint.Value, quantity fixedpoint.Value) bool {
|
||||
refPrice := fixedpoint.NewFromFloat(r.referencePrice.Last(0))
|
||||
// calculate profit
|
||||
var profit fixedpoint.Value
|
||||
if side == types.SideTypeBuy {
|
||||
profit = refPrice.Sub(price).Mul(quantity)
|
||||
} else if side == types.SideTypeSell {
|
||||
profit = price.Sub(refPrice).Mul(quantity)
|
||||
}
|
||||
return profit.Compare(r.lossThreshold) > 0
|
||||
}
|
||||
|
||||
func (r *PriceRiskControl) IsSafeLimitOrder(o types.SubmitOrder) (bool, error) {
|
||||
if !(o.Type == types.OrderTypeLimit || o.Type == types.OrderTypeLimitMaker) {
|
||||
return false, fmt.Errorf("order type is not limit order")
|
||||
}
|
||||
return r.IsSafe(o.Side, o.Price, o.Quantity), nil
|
||||
}
|
63
pkg/risk/riskcontrol/price_test.go
Normal file
63
pkg/risk/riskcontrol/price_test.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
package riskcontrol
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
func Test_IsSafe(t *testing.T) {
|
||||
refPrice := 30000.00
|
||||
lossThreshold := fixedpoint.NewFromFloat(-100)
|
||||
|
||||
window := types.IntervalWindow{Window: 30, Interval: types.Interval1m}
|
||||
refPriceEWMA := indicatorv2.EWMA2(nil, window.Window)
|
||||
refPriceEWMA.PushAndEmit(refPrice)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
side types.SideType
|
||||
price fixedpoint.Value
|
||||
quantity fixedpoint.Value
|
||||
isSafe bool
|
||||
}{
|
||||
{
|
||||
name: "BuyingHighSafe",
|
||||
side: types.SideTypeBuy,
|
||||
price: fixedpoint.NewFromFloat(30040.0),
|
||||
quantity: fixedpoint.NewFromFloat(1.0),
|
||||
isSafe: true,
|
||||
},
|
||||
{
|
||||
name: "SellingLowSafe",
|
||||
side: types.SideTypeSell,
|
||||
price: fixedpoint.NewFromFloat(29960.0),
|
||||
quantity: fixedpoint.NewFromFloat(1.0),
|
||||
isSafe: true,
|
||||
},
|
||||
{
|
||||
name: "BuyingHighLoss",
|
||||
side: types.SideTypeBuy,
|
||||
price: fixedpoint.NewFromFloat(30040.0),
|
||||
quantity: fixedpoint.NewFromFloat(10.0),
|
||||
isSafe: false,
|
||||
},
|
||||
{
|
||||
name: "SellingLowLoss",
|
||||
side: types.SideTypeSell,
|
||||
price: fixedpoint.NewFromFloat(29960.0),
|
||||
quantity: fixedpoint.NewFromFloat(10.0),
|
||||
isSafe: false,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var riskControl = NewPriceRiskControl(refPriceEWMA, lossThreshold)
|
||||
assert.Equal(t, tc.isSafe, riskControl.IsSafe(tc.side, tc.price, tc.quantity))
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user