2023-06-29 07:06:03 +00:00
|
|
|
package riskcontrol
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
2024-03-12 05:09:59 +00:00
|
|
|
"go.uber.org/mock/gomock"
|
2023-06-29 07:06:03 +00:00
|
|
|
|
|
|
|
"github.com/c9s/bbgo/pkg/bbgo"
|
2023-07-04 14:07:31 +00:00
|
|
|
"github.com/c9s/bbgo/pkg/bbgo/mocks"
|
2023-07-05 07:26:36 +00:00
|
|
|
"github.com/c9s/bbgo/pkg/core"
|
2023-06-29 07:06:03 +00:00
|
|
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
|
|
|
"github.com/c9s/bbgo/pkg/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
func Test_ModifiedQuantity(t *testing.T) {
|
2023-07-04 13:31:47 +00:00
|
|
|
pos := &types.Position{
|
|
|
|
Market: types.Market{
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
PricePrecision: 8,
|
|
|
|
VolumePrecision: 8,
|
|
|
|
QuoteCurrency: "USDT",
|
|
|
|
BaseCurrency: "BTC",
|
|
|
|
},
|
|
|
|
}
|
2024-08-20 06:10:22 +00:00
|
|
|
orderExecutor := bbgo.NewGeneralOrderExecutor(&bbgo.ExchangeSession{}, "BTCUSDT", "strategy", "strategy-1", pos)
|
2023-07-04 13:32:34 +00:00
|
|
|
riskControl := NewPositionRiskControl(orderExecutor, fixedpoint.NewFromInt(10), fixedpoint.NewFromInt(2))
|
2023-06-29 07:06:03 +00:00
|
|
|
|
|
|
|
cases := []struct {
|
|
|
|
name string
|
|
|
|
position fixedpoint.Value
|
|
|
|
buyQuantity fixedpoint.Value
|
|
|
|
sellQuantity fixedpoint.Value
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "BuyOverHardLimit",
|
|
|
|
position: fixedpoint.NewFromInt(9),
|
|
|
|
buyQuantity: fixedpoint.NewFromInt(1),
|
|
|
|
sellQuantity: fixedpoint.NewFromInt(2),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "SellOverHardLimit",
|
|
|
|
position: fixedpoint.NewFromInt(-9),
|
|
|
|
buyQuantity: fixedpoint.NewFromInt(2),
|
|
|
|
sellQuantity: fixedpoint.NewFromInt(1),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
buyQuantity, sellQuantity := riskControl.ModifiedQuantity(tc.position)
|
|
|
|
assert.Equal(t, tc.buyQuantity, buyQuantity)
|
|
|
|
assert.Equal(t, tc.sellQuantity, sellQuantity)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestReleasePositionCallbacks(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
name string
|
|
|
|
position fixedpoint.Value
|
|
|
|
resultPosition fixedpoint.Value
|
|
|
|
}{
|
|
|
|
{
|
2023-07-04 14:07:31 +00:00
|
|
|
name: "PositivePositionWithinLimit",
|
2023-06-29 07:06:03 +00:00
|
|
|
position: fixedpoint.NewFromInt(8),
|
|
|
|
resultPosition: fixedpoint.NewFromInt(8),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "NegativePositionWithinLimit",
|
|
|
|
position: fixedpoint.NewFromInt(-8),
|
|
|
|
resultPosition: fixedpoint.NewFromInt(-8),
|
|
|
|
},
|
|
|
|
{
|
2023-07-04 14:07:31 +00:00
|
|
|
name: "PositivePositionOverLimit",
|
2023-06-29 07:06:03 +00:00
|
|
|
position: fixedpoint.NewFromInt(11),
|
|
|
|
resultPosition: fixedpoint.NewFromInt(10),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "NegativePositionOverLimit",
|
|
|
|
position: fixedpoint.NewFromInt(-11),
|
|
|
|
resultPosition: fixedpoint.NewFromInt(-10),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
2023-07-04 13:31:47 +00:00
|
|
|
pos := &types.Position{
|
|
|
|
Base: tc.position,
|
|
|
|
Market: types.Market{
|
|
|
|
Symbol: "BTCUSDT",
|
|
|
|
PricePrecision: 8,
|
|
|
|
VolumePrecision: 8,
|
|
|
|
QuoteCurrency: "USDT",
|
|
|
|
BaseCurrency: "BTC",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-07-05 07:26:36 +00:00
|
|
|
tradeCollector := &core.TradeCollector{}
|
2023-07-04 14:07:31 +00:00
|
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
defer mockCtrl.Finish()
|
|
|
|
orderExecutor := mocks.NewMockOrderExecutorExtended(mockCtrl)
|
|
|
|
orderExecutor.EXPECT().TradeCollector().Return(tradeCollector).AnyTimes()
|
|
|
|
orderExecutor.EXPECT().Position().Return(pos).AnyTimes()
|
|
|
|
orderExecutor.EXPECT().SubmitOrders(gomock.Any(), gomock.Any()).AnyTimes()
|
|
|
|
|
2023-07-04 13:32:34 +00:00
|
|
|
riskControl := NewPositionRiskControl(orderExecutor, fixedpoint.NewFromInt(10), fixedpoint.NewFromInt(2))
|
2023-07-04 13:31:47 +00:00
|
|
|
riskControl.OnReleasePosition(func(quantity fixedpoint.Value, side types.SideType) {
|
|
|
|
if side == types.SideTypeBuy {
|
|
|
|
pos.Base = pos.Base.Add(quantity)
|
|
|
|
} else {
|
|
|
|
pos.Base = pos.Base.Sub(quantity)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
orderExecutor.TradeCollector().EmitPositionUpdate(&types.Position{Base: tc.position})
|
|
|
|
assert.Equal(t, tc.resultPosition, pos.Base)
|
2023-06-29 07:06:03 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|