mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
Merge pull request #1220 from c9s/feature/scmaker-with-risk-control
REFACTOR: refactor risk control with the order executor interface and mocks
This commit is contained in:
commit
b9b89756e2
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/sigchan"
|
"github.com/c9s/bbgo/pkg/sigchan"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
@ -16,6 +17,7 @@ import (
|
||||||
const CancelOrderWaitTime = 20 * time.Millisecond
|
const CancelOrderWaitTime = 20 * time.Millisecond
|
||||||
|
|
||||||
// ActiveOrderBook manages the local active order books.
|
// ActiveOrderBook manages the local active order books.
|
||||||
|
//
|
||||||
//go:generate callbackgen -type ActiveOrderBook
|
//go:generate callbackgen -type ActiveOrderBook
|
||||||
type ActiveOrderBook struct {
|
type ActiveOrderBook struct {
|
||||||
Symbol string
|
Symbol string
|
||||||
|
@ -209,7 +211,7 @@ func (b *ActiveOrderBook) GracefulCancel(ctx context.Context, ex types.Exchange,
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
openOrderStore := NewOrderStore(symbol)
|
openOrderStore := core.NewOrderStore(symbol)
|
||||||
openOrderStore.Add(openOrders...)
|
openOrderStore.Add(openOrders...)
|
||||||
for _, o := range orders {
|
for _, o := range orders {
|
||||||
// if it's not on the order book (open orders), we should remove it from our local side
|
// if it's not on the order book (open orders), we should remove it from our local side
|
||||||
|
|
104
pkg/bbgo/mocks/mock_order_executor_extended.go
Normal file
104
pkg/bbgo/mocks/mock_order_executor_extended.go
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
|
// Source: github.com/c9s/bbgo/pkg/bbgo (interfaces: OrderExecutorExtended)
|
||||||
|
|
||||||
|
// Package mocks is a generated GoMock package.
|
||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
|
bbgo "github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
types "github.com/c9s/bbgo/pkg/types"
|
||||||
|
gomock "github.com/golang/mock/gomock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockOrderExecutorExtended is a mock of OrderExecutorExtended interface.
|
||||||
|
type MockOrderExecutorExtended struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockOrderExecutorExtendedMockRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockOrderExecutorExtendedMockRecorder is the mock recorder for MockOrderExecutorExtended.
|
||||||
|
type MockOrderExecutorExtendedMockRecorder struct {
|
||||||
|
mock *MockOrderExecutorExtended
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockOrderExecutorExtended creates a new mock instance.
|
||||||
|
func NewMockOrderExecutorExtended(ctrl *gomock.Controller) *MockOrderExecutorExtended {
|
||||||
|
mock := &MockOrderExecutorExtended{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockOrderExecutorExtendedMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
|
func (m *MockOrderExecutorExtended) EXPECT() *MockOrderExecutorExtendedMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelOrders mocks base method.
|
||||||
|
func (m *MockOrderExecutorExtended) CancelOrders(arg0 context.Context, arg1 ...types.Order) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0}
|
||||||
|
for _, a := range arg1 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "CancelOrders", varargs...)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelOrders indicates an expected call of CancelOrders.
|
||||||
|
func (mr *MockOrderExecutorExtendedMockRecorder) CancelOrders(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0}, arg1...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelOrders", reflect.TypeOf((*MockOrderExecutorExtended)(nil).CancelOrders), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position mocks base method.
|
||||||
|
func (m *MockOrderExecutorExtended) Position() *types.Position {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "Position")
|
||||||
|
ret0, _ := ret[0].(*types.Position)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position indicates an expected call of Position.
|
||||||
|
func (mr *MockOrderExecutorExtendedMockRecorder) Position() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Position", reflect.TypeOf((*MockOrderExecutorExtended)(nil).Position))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitOrders mocks base method.
|
||||||
|
func (m *MockOrderExecutorExtended) SubmitOrders(arg0 context.Context, arg1 ...types.SubmitOrder) (types.OrderSlice, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
varargs := []interface{}{arg0}
|
||||||
|
for _, a := range arg1 {
|
||||||
|
varargs = append(varargs, a)
|
||||||
|
}
|
||||||
|
ret := m.ctrl.Call(m, "SubmitOrders", varargs...)
|
||||||
|
ret0, _ := ret[0].(types.OrderSlice)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitOrders indicates an expected call of SubmitOrders.
|
||||||
|
func (mr *MockOrderExecutorExtendedMockRecorder) SubmitOrders(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
varargs := append([]interface{}{arg0}, arg1...)
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitOrders", reflect.TypeOf((*MockOrderExecutorExtended)(nil).SubmitOrders), varargs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TradeCollector mocks base method.
|
||||||
|
func (m *MockOrderExecutorExtended) TradeCollector() *bbgo.TradeCollector {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "TradeCollector")
|
||||||
|
ret0, _ := ret[0].(*bbgo.TradeCollector)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// TradeCollector indicates an expected call of TradeCollector.
|
||||||
|
func (mr *MockOrderExecutorExtendedMockRecorder) TradeCollector() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TradeCollector", reflect.TypeOf((*MockOrderExecutorExtended)(nil).TradeCollector))
|
||||||
|
}
|
|
@ -28,6 +28,14 @@ type OrderExecutor interface {
|
||||||
CancelOrders(ctx context.Context, orders ...types.Order) error
|
CancelOrders(ctx context.Context, orders ...types.Order) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:generate mockgen -destination=mocks/mock_order_executor_extended.go -package=mocks . OrderExecutorExtended
|
||||||
|
type OrderExecutorExtended interface {
|
||||||
|
SubmitOrders(ctx context.Context, orders ...types.SubmitOrder) (createdOrders types.OrderSlice, err error)
|
||||||
|
CancelOrders(ctx context.Context, orders ...types.Order) error
|
||||||
|
TradeCollector() *TradeCollector
|
||||||
|
Position() *types.Position
|
||||||
|
}
|
||||||
|
|
||||||
type OrderExecutionRouter interface {
|
type OrderExecutionRouter interface {
|
||||||
// SubmitOrdersTo submit order to a specific exchange Session
|
// SubmitOrdersTo submit order to a specific exchange Session
|
||||||
SubmitOrdersTo(ctx context.Context, session string, orders ...types.SubmitOrder) (createdOrders types.OrderSlice, err error)
|
SubmitOrdersTo(ctx context.Context, session string, orders ...types.SubmitOrder) (createdOrders types.OrderSlice, err error)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"go.uber.org/multierr"
|
"go.uber.org/multierr"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/exchange/retry"
|
"github.com/c9s/bbgo/pkg/exchange/retry"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
@ -33,7 +34,7 @@ type GeneralOrderExecutor struct {
|
||||||
strategyInstanceID string
|
strategyInstanceID string
|
||||||
position *types.Position
|
position *types.Position
|
||||||
activeMakerOrders *ActiveOrderBook
|
activeMakerOrders *ActiveOrderBook
|
||||||
orderStore *OrderStore
|
orderStore *core.OrderStore
|
||||||
tradeCollector *TradeCollector
|
tradeCollector *TradeCollector
|
||||||
|
|
||||||
logger log.FieldLogger
|
logger log.FieldLogger
|
||||||
|
@ -49,7 +50,7 @@ func NewGeneralOrderExecutor(session *ExchangeSession, symbol, strategy, strateg
|
||||||
position.Strategy = strategy
|
position.Strategy = strategy
|
||||||
position.StrategyInstanceID = strategyInstanceID
|
position.StrategyInstanceID = strategyInstanceID
|
||||||
|
|
||||||
orderStore := NewOrderStore(symbol)
|
orderStore := core.NewOrderStore(symbol)
|
||||||
|
|
||||||
executor := &GeneralOrderExecutor{
|
executor := &GeneralOrderExecutor{
|
||||||
session: session,
|
session: session,
|
||||||
|
@ -62,7 +63,7 @@ func NewGeneralOrderExecutor(session *ExchangeSession, symbol, strategy, strateg
|
||||||
tradeCollector: NewTradeCollector(symbol, position, orderStore),
|
tradeCollector: NewTradeCollector(symbol, position, orderStore),
|
||||||
}
|
}
|
||||||
|
|
||||||
if session.Margin {
|
if session != nil && session.Margin {
|
||||||
executor.startMarginAssetUpdater(context.Background())
|
executor.startMarginAssetUpdater(context.Background())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +122,7 @@ func (e *GeneralOrderExecutor) marginAssetMaxBorrowableUpdater(ctx context.Conte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *GeneralOrderExecutor) OrderStore() *OrderStore {
|
func (e *GeneralOrderExecutor) OrderStore() *core.OrderStore {
|
||||||
return e.orderStore
|
return e.orderStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/cache"
|
"github.com/c9s/bbgo/pkg/cache"
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/util/templateutil"
|
"github.com/c9s/bbgo/pkg/util/templateutil"
|
||||||
|
|
||||||
exchange2 "github.com/c9s/bbgo/pkg/exchange"
|
exchange2 "github.com/c9s/bbgo/pkg/exchange"
|
||||||
|
@ -110,7 +111,7 @@ type ExchangeSession struct {
|
||||||
// indicators is the v2 api indicators
|
// indicators is the v2 api indicators
|
||||||
indicators map[string]*IndicatorSet
|
indicators map[string]*IndicatorSet
|
||||||
|
|
||||||
orderStores map[string]*OrderStore
|
orderStores map[string]*core.OrderStore
|
||||||
|
|
||||||
usedSymbols map[string]struct{}
|
usedSymbols map[string]struct{}
|
||||||
initializedSymbols map[string]struct{}
|
initializedSymbols map[string]struct{}
|
||||||
|
@ -140,7 +141,7 @@ func NewExchangeSession(name string, exchange types.Exchange) *ExchangeSession {
|
||||||
marketDataStores: make(map[string]*MarketDataStore),
|
marketDataStores: make(map[string]*MarketDataStore),
|
||||||
standardIndicatorSets: make(map[string]*StandardIndicatorSet),
|
standardIndicatorSets: make(map[string]*StandardIndicatorSet),
|
||||||
indicators: make(map[string]*IndicatorSet),
|
indicators: make(map[string]*IndicatorSet),
|
||||||
orderStores: make(map[string]*OrderStore),
|
orderStores: make(map[string]*core.OrderStore),
|
||||||
usedSymbols: make(map[string]struct{}),
|
usedSymbols: make(map[string]struct{}),
|
||||||
initializedSymbols: make(map[string]struct{}),
|
initializedSymbols: make(map[string]struct{}),
|
||||||
logger: log.WithField("session", name),
|
logger: log.WithField("session", name),
|
||||||
|
@ -398,7 +399,7 @@ func (session *ExchangeSession) initSymbol(ctx context.Context, environ *Environ
|
||||||
position.BindStream(session.UserDataStream)
|
position.BindStream(session.UserDataStream)
|
||||||
session.positions[symbol] = position
|
session.positions[symbol] = position
|
||||||
|
|
||||||
orderStore := NewOrderStore(symbol)
|
orderStore := core.NewOrderStore(symbol)
|
||||||
orderStore.AddOrderUpdate = true
|
orderStore.AddOrderUpdate = true
|
||||||
|
|
||||||
orderStore.BindStream(session.UserDataStream)
|
orderStore.BindStream(session.UserDataStream)
|
||||||
|
@ -615,12 +616,12 @@ func (session *ExchangeSession) Markets() map[string]types.Market {
|
||||||
return session.markets
|
return session.markets
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *ExchangeSession) OrderStore(symbol string) (store *OrderStore, ok bool) {
|
func (session *ExchangeSession) OrderStore(symbol string) (store *core.OrderStore, ok bool) {
|
||||||
store, ok = session.orderStores[symbol]
|
store, ok = session.orderStores[symbol]
|
||||||
return store, ok
|
return store, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *ExchangeSession) OrderStores() map[string]*OrderStore {
|
func (session *ExchangeSession) OrderStores() map[string]*core.OrderStore {
|
||||||
return session.orderStores
|
return session.orderStores
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,7 +810,7 @@ func (session *ExchangeSession) InitExchange(name string, ex types.Exchange) err
|
||||||
session.positions = make(map[string]*types.Position)
|
session.positions = make(map[string]*types.Position)
|
||||||
session.standardIndicatorSets = make(map[string]*StandardIndicatorSet)
|
session.standardIndicatorSets = make(map[string]*StandardIndicatorSet)
|
||||||
session.indicators = make(map[string]*IndicatorSet)
|
session.indicators = make(map[string]*IndicatorSet)
|
||||||
session.orderStores = make(map[string]*OrderStore)
|
session.orderStores = make(map[string]*core.OrderStore)
|
||||||
session.OrderExecutor = &ExchangeOrderExecutor{
|
session.OrderExecutor = &ExchangeOrderExecutor{
|
||||||
// copy the notification system so that we can route
|
// copy the notification system so that we can route
|
||||||
Session: session,
|
Session: session,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/sigchan"
|
"github.com/c9s/bbgo/pkg/sigchan"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
@ -17,10 +18,10 @@ type TradeCollector struct {
|
||||||
Symbol string
|
Symbol string
|
||||||
orderSig sigchan.Chan
|
orderSig sigchan.Chan
|
||||||
|
|
||||||
tradeStore *TradeStore
|
tradeStore *core.TradeStore
|
||||||
tradeC chan types.Trade
|
tradeC chan types.Trade
|
||||||
position *types.Position
|
position *types.Position
|
||||||
orderStore *OrderStore
|
orderStore *core.OrderStore
|
||||||
doneTrades map[types.TradeKey]struct{}
|
doneTrades map[types.TradeKey]struct{}
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
@ -33,13 +34,13 @@ type TradeCollector struct {
|
||||||
profitCallbacks []func(trade types.Trade, profit *types.Profit)
|
profitCallbacks []func(trade types.Trade, profit *types.Profit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTradeCollector(symbol string, position *types.Position, orderStore *OrderStore) *TradeCollector {
|
func NewTradeCollector(symbol string, position *types.Position, orderStore *core.OrderStore) *TradeCollector {
|
||||||
return &TradeCollector{
|
return &TradeCollector{
|
||||||
Symbol: symbol,
|
Symbol: symbol,
|
||||||
orderSig: sigchan.New(1),
|
orderSig: sigchan.New(1),
|
||||||
|
|
||||||
tradeC: make(chan types.Trade, 100),
|
tradeC: make(chan types.Trade, 100),
|
||||||
tradeStore: NewTradeStore(),
|
tradeStore: core.NewTradeStore(),
|
||||||
doneTrades: make(map[types.TradeKey]struct{}),
|
doneTrades: make(map[types.TradeKey]struct{}),
|
||||||
position: position,
|
position: position,
|
||||||
orderStore: orderStore,
|
orderStore: orderStore,
|
||||||
|
@ -47,7 +48,7 @@ func NewTradeCollector(symbol string, position *types.Position, orderStore *Orde
|
||||||
}
|
}
|
||||||
|
|
||||||
// OrderStore returns the order store used by the trade collector
|
// OrderStore returns the order store used by the trade collector
|
||||||
func (c *TradeCollector) OrderStore() *OrderStore {
|
func (c *TradeCollector) OrderStore() *core.OrderStore {
|
||||||
return c.orderStore
|
return c.orderStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ func (c *TradeCollector) Position() *types.Position {
|
||||||
return c.position
|
return c.position
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TradeCollector) TradeStore() *TradeStore {
|
func (c *TradeCollector) TradeStore() *core.TradeStore {
|
||||||
return c.tradeStore
|
return c.tradeStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
@ -12,7 +13,7 @@ import (
|
||||||
func TestTradeCollector_ShouldNotCountDuplicatedTrade(t *testing.T) {
|
func TestTradeCollector_ShouldNotCountDuplicatedTrade(t *testing.T) {
|
||||||
symbol := "BTCUSDT"
|
symbol := "BTCUSDT"
|
||||||
position := types.NewPosition(symbol, "BTC", "USDT")
|
position := types.NewPosition(symbol, "BTC", "USDT")
|
||||||
orderStore := NewOrderStore(symbol)
|
orderStore := core.NewOrderStore(symbol)
|
||||||
collector := NewTradeCollector(symbol, position, orderStore)
|
collector := NewTradeCollector(symbol, position, orderStore)
|
||||||
assert.NotNil(t, collector)
|
assert.NotNil(t, collector)
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
@ -37,7 +38,7 @@ type TwapExecution struct {
|
||||||
activePosition fixedpoint.Value
|
activePosition fixedpoint.Value
|
||||||
|
|
||||||
activeMakerOrders *ActiveOrderBook
|
activeMakerOrders *ActiveOrderBook
|
||||||
orderStore *OrderStore
|
orderStore *core.OrderStore
|
||||||
position *types.Position
|
position *types.Position
|
||||||
|
|
||||||
executionCtx context.Context
|
executionCtx context.Context
|
||||||
|
@ -406,7 +407,7 @@ func (e *TwapExecution) Run(parentCtx context.Context) error {
|
||||||
QuoteCurrency: e.market.QuoteCurrency,
|
QuoteCurrency: e.market.QuoteCurrency,
|
||||||
}
|
}
|
||||||
|
|
||||||
e.orderStore = NewOrderStore(e.Symbol)
|
e.orderStore = core.NewOrderStore(e.Symbol)
|
||||||
e.orderStore.BindStream(e.userDataStream)
|
e.orderStore.BindStream(e.userDataStream)
|
||||||
e.activeMakerOrders = NewActiveOrderBook(e.Symbol)
|
e.activeMakerOrders = NewActiveOrderBook(e.Symbol)
|
||||||
e.activeMakerOrders.OnFilled(e.handleFilledOrder)
|
e.activeMakerOrders.OnFilled(e.handleFilledOrder)
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/cmd/cmdutil"
|
"github.com/c9s/bbgo/pkg/cmd/cmdutil"
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/data/tsv"
|
"github.com/c9s/bbgo/pkg/data/tsv"
|
||||||
"github.com/c9s/bbgo/pkg/util"
|
"github.com/c9s/bbgo/pkg/util"
|
||||||
|
|
||||||
|
@ -314,7 +315,7 @@ var BacktestCmd = &cobra.Command{
|
||||||
for usedSymbol := range exSource.Session.Positions() {
|
for usedSymbol := range exSource.Session.Positions() {
|
||||||
market, _ := exSource.Session.Market(usedSymbol)
|
market, _ := exSource.Session.Market(usedSymbol)
|
||||||
position := types.NewPositionFromMarket(market)
|
position := types.NewPositionFromMarket(market)
|
||||||
orderStore := bbgo.NewOrderStore(usedSymbol)
|
orderStore := core.NewOrderStore(usedSymbol)
|
||||||
orderStore.AddOrderUpdate = true
|
orderStore.AddOrderUpdate = true
|
||||||
tradeCollector := bbgo.NewTradeCollector(usedSymbol, position, orderStore)
|
tradeCollector := bbgo.NewTradeCollector(usedSymbol, position, orderStore)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package bbgo
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
|
@ -1,4 +1,4 @@
|
||||||
package bbgo
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
|
@ -1,4 +1,4 @@
|
||||||
package bbgo
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
|
@ -1,6 +1,8 @@
|
||||||
package riskcontrol
|
package riskcontrol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
@ -8,38 +10,76 @@ import (
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PositionRiskControl controls the position with the given hard limit
|
||||||
|
// TODO: add a decorator for the order executor and move the order submission logics into the decorator
|
||||||
|
//
|
||||||
//go:generate callbackgen -type PositionRiskControl
|
//go:generate callbackgen -type PositionRiskControl
|
||||||
type PositionRiskControl struct {
|
type PositionRiskControl struct {
|
||||||
|
orderExecutor bbgo.OrderExecutorExtended
|
||||||
|
|
||||||
|
// hardLimit is the maximum base position you can hold
|
||||||
hardLimit fixedpoint.Value
|
hardLimit fixedpoint.Value
|
||||||
quantity fixedpoint.Value
|
|
||||||
|
// sliceQuantity is the maximum quantity of the order you want to place.
|
||||||
|
// only used in the ModifiedQuantity method
|
||||||
|
sliceQuantity fixedpoint.Value
|
||||||
|
|
||||||
releasePositionCallbacks []func(quantity fixedpoint.Value, side types.SideType)
|
releasePositionCallbacks []func(quantity fixedpoint.Value, side types.SideType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPositionRiskControl(hardLimit, quantity fixedpoint.Value, tradeCollector *bbgo.TradeCollector) *PositionRiskControl {
|
func NewPositionRiskControl(orderExecutor bbgo.OrderExecutorExtended, hardLimit, quantity fixedpoint.Value) *PositionRiskControl {
|
||||||
p := &PositionRiskControl{
|
control := &PositionRiskControl{
|
||||||
|
orderExecutor: orderExecutor,
|
||||||
hardLimit: hardLimit,
|
hardLimit: hardLimit,
|
||||||
quantity: quantity,
|
sliceQuantity: quantity,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
control.OnReleasePosition(func(quantity fixedpoint.Value, side types.SideType) {
|
||||||
|
pos := orderExecutor.Position()
|
||||||
|
createdOrders, err := orderExecutor.SubmitOrders(context.Background(), types.SubmitOrder{
|
||||||
|
Symbol: pos.Symbol,
|
||||||
|
Market: pos.Market,
|
||||||
|
Side: side,
|
||||||
|
Type: types.OrderTypeMarket,
|
||||||
|
Quantity: quantity,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Errorf("failed to submit orders")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("created position release orders: %+v", createdOrders)
|
||||||
|
})
|
||||||
|
|
||||||
// register position update handler: check if position is over the hard limit
|
// register position update handler: check if position is over the hard limit
|
||||||
tradeCollector.OnPositionUpdate(func(position *types.Position) {
|
orderExecutor.TradeCollector().OnPositionUpdate(func(position *types.Position) {
|
||||||
if fixedpoint.Compare(position.Base, hardLimit) > 0 {
|
if fixedpoint.Compare(position.Base, hardLimit) > 0 {
|
||||||
log.Infof("position %f is over hardlimit %f, releasing position...", position.Base.Float64(), hardLimit.Float64())
|
log.Infof("position %f is over hardlimit %f, releasing position...", position.Base.Float64(), hardLimit.Float64())
|
||||||
p.EmitReleasePosition(position.Base.Sub(hardLimit), types.SideTypeSell)
|
control.EmitReleasePosition(position.Base.Sub(hardLimit), types.SideTypeSell)
|
||||||
} else if fixedpoint.Compare(position.Base, hardLimit.Neg()) < 0 {
|
} else if fixedpoint.Compare(position.Base, hardLimit.Neg()) < 0 {
|
||||||
log.Infof("position %f is over hardlimit %f, releasing position...", position.Base.Float64(), hardLimit.Float64())
|
log.Infof("position %f is over hardlimit %f, releasing position...", position.Base.Float64(), hardLimit.Float64())
|
||||||
p.EmitReleasePosition(position.Base.Neg().Sub(hardLimit), types.SideTypeBuy)
|
control.EmitReleasePosition(position.Base.Neg().Sub(hardLimit), types.SideTypeBuy)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return p
|
return control
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModifiedQuantity returns quantity controlled by position risks
|
// ModifiedQuantity returns sliceQuantity controlled by position risks
|
||||||
// For buy orders, mod quantity = min(hardLimit - position, quantity), limiting by positive position
|
// For buy orders, modify sliceQuantity = min(hardLimit - position, sliceQuantity), limiting by positive position
|
||||||
// For sell orders, mod quantity = min(hardLimit - (-position), quantity), limiting by negative position
|
// For sell orders, modify sliceQuantity = min(hardLimit - (-position), sliceQuantity), limiting by negative position
|
||||||
|
//
|
||||||
|
// Pass the current base position to this method, and it returns the maximum sliceQuantity for placing the orders.
|
||||||
|
// This works for both Long/Short position
|
||||||
func (p *PositionRiskControl) ModifiedQuantity(position fixedpoint.Value) (buyQuantity, sellQuantity fixedpoint.Value) {
|
func (p *PositionRiskControl) ModifiedQuantity(position fixedpoint.Value) (buyQuantity, sellQuantity fixedpoint.Value) {
|
||||||
return fixedpoint.Min(p.hardLimit.Sub(position), p.quantity),
|
if p.sliceQuantity.IsZero() {
|
||||||
fixedpoint.Min(p.hardLimit.Add(position), p.quantity)
|
buyQuantity = p.hardLimit.Sub(position)
|
||||||
|
sellQuantity = p.hardLimit.Add(position)
|
||||||
|
return buyQuantity, sellQuantity
|
||||||
|
}
|
||||||
|
|
||||||
|
buyQuantity = fixedpoint.Min(p.hardLimit.Sub(position), p.sliceQuantity)
|
||||||
|
sellQuantity = fixedpoint.Min(p.hardLimit.Add(position), p.sliceQuantity)
|
||||||
|
return buyQuantity, sellQuantity
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,27 @@ package riskcontrol
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
"github.com/c9s/bbgo/pkg/bbgo/mocks"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_ModifiedQuantity(t *testing.T) {
|
func Test_ModifiedQuantity(t *testing.T) {
|
||||||
|
pos := &types.Position{
|
||||||
riskControl := NewPositionRiskControl(fixedpoint.NewFromInt(10), fixedpoint.NewFromInt(2), &bbgo.TradeCollector{})
|
Market: types.Market{
|
||||||
|
Symbol: "BTCUSDT",
|
||||||
|
PricePrecision: 8,
|
||||||
|
VolumePrecision: 8,
|
||||||
|
QuoteCurrency: "USDT",
|
||||||
|
BaseCurrency: "BTC",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
orderExecutor := bbgo.NewGeneralOrderExecutor(nil, "BTCUSDT", "strategy", "strategy-1", pos)
|
||||||
|
riskControl := NewPositionRiskControl(orderExecutor, fixedpoint.NewFromInt(10), fixedpoint.NewFromInt(2))
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -43,26 +54,13 @@ func Test_ModifiedQuantity(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReleasePositionCallbacks(t *testing.T) {
|
func TestReleasePositionCallbacks(t *testing.T) {
|
||||||
|
|
||||||
var position fixedpoint.Value
|
|
||||||
|
|
||||||
tradeCollector := &bbgo.TradeCollector{}
|
|
||||||
riskControl := NewPositionRiskControl(fixedpoint.NewFromInt(10), fixedpoint.NewFromInt(2), tradeCollector)
|
|
||||||
riskControl.OnReleasePosition(func(quantity fixedpoint.Value, side types.SideType) {
|
|
||||||
if side == types.SideTypeBuy {
|
|
||||||
position = position.Add(quantity)
|
|
||||||
} else {
|
|
||||||
position = position.Sub(quantity)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
position fixedpoint.Value
|
position fixedpoint.Value
|
||||||
resultPosition fixedpoint.Value
|
resultPosition fixedpoint.Value
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "PostivePositionWithinLimit",
|
name: "PositivePositionWithinLimit",
|
||||||
position: fixedpoint.NewFromInt(8),
|
position: fixedpoint.NewFromInt(8),
|
||||||
resultPosition: fixedpoint.NewFromInt(8),
|
resultPosition: fixedpoint.NewFromInt(8),
|
||||||
},
|
},
|
||||||
|
@ -72,7 +70,7 @@ func TestReleasePositionCallbacks(t *testing.T) {
|
||||||
resultPosition: fixedpoint.NewFromInt(-8),
|
resultPosition: fixedpoint.NewFromInt(-8),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PostivePositionOverLimit",
|
name: "PositivePositionOverLimit",
|
||||||
position: fixedpoint.NewFromInt(11),
|
position: fixedpoint.NewFromInt(11),
|
||||||
resultPosition: fixedpoint.NewFromInt(10),
|
resultPosition: fixedpoint.NewFromInt(10),
|
||||||
},
|
},
|
||||||
|
@ -84,9 +82,36 @@ func TestReleasePositionCallbacks(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
position = tc.position
|
pos := &types.Position{
|
||||||
tradeCollector.EmitPositionUpdate(&types.Position{Base: tc.position})
|
Base: tc.position,
|
||||||
assert.Equal(t, tc.resultPosition, position)
|
Market: types.Market{
|
||||||
|
Symbol: "BTCUSDT",
|
||||||
|
PricePrecision: 8,
|
||||||
|
VolumePrecision: 8,
|
||||||
|
QuoteCurrency: "USDT",
|
||||||
|
BaseCurrency: "BTC",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tradeCollector := &bbgo.TradeCollector{}
|
||||||
|
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()
|
||||||
|
|
||||||
|
riskControl := NewPositionRiskControl(orderExecutor, fixedpoint.NewFromInt(10), fixedpoint.NewFromInt(2))
|
||||||
|
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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/indicator"
|
"github.com/c9s/bbgo/pkg/indicator"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
@ -71,7 +72,7 @@ type Strategy struct {
|
||||||
|
|
||||||
profitOrders *bbgo.ActiveOrderBook
|
profitOrders *bbgo.ActiveOrderBook
|
||||||
|
|
||||||
orders *bbgo.OrderStore
|
orders *core.OrderStore
|
||||||
|
|
||||||
// boll is the BOLLINGER indicator we used for predicting the price.
|
// boll is the BOLLINGER indicator we used for predicting the price.
|
||||||
boll *indicator.BOLL
|
boll *indicator.BOLL
|
||||||
|
@ -330,7 +331,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
Window: 21,
|
Window: 21,
|
||||||
}, 2.0)
|
}, 2.0)
|
||||||
|
|
||||||
s.orders = bbgo.NewOrderStore(s.Symbol)
|
s.orders = core.NewOrderStore(s.Symbol)
|
||||||
s.orders.BindStream(session.UserDataStream)
|
s.orders.BindStream(session.UserDataStream)
|
||||||
|
|
||||||
// we don't persist orders so that we can not clear the previous orders for now. just need time to support this.
|
// we don't persist orders so that we can not clear the previous orders for now. just need time to support this.
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"gonum.org/v1/gonum/floats"
|
"gonum.org/v1/gonum/floats"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
floats2 "github.com/c9s/bbgo/pkg/datatype/floats"
|
floats2 "github.com/c9s/bbgo/pkg/datatype/floats"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
@ -47,7 +48,7 @@ type Strategy struct {
|
||||||
activeMakerOrders *bbgo.ActiveOrderBook
|
activeMakerOrders *bbgo.ActiveOrderBook
|
||||||
// closePositionOrders *bbgo.LocalActiveOrderBook
|
// closePositionOrders *bbgo.LocalActiveOrderBook
|
||||||
|
|
||||||
orderStore *bbgo.OrderStore
|
orderStore *core.OrderStore
|
||||||
tradeCollector *bbgo.TradeCollector
|
tradeCollector *bbgo.TradeCollector
|
||||||
|
|
||||||
session *bbgo.ExchangeSession
|
session *bbgo.ExchangeSession
|
||||||
|
@ -158,7 +159,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
// s.closePositionOrders = bbgo.NewLocalActiveOrderBook(s.Symbol)
|
// s.closePositionOrders = bbgo.NewLocalActiveOrderBook(s.Symbol)
|
||||||
// s.closePositionOrders.BindStream(session.UserDataStream)
|
// s.closePositionOrders.BindStream(session.UserDataStream)
|
||||||
|
|
||||||
s.orderStore = bbgo.NewOrderStore(s.Symbol)
|
s.orderStore = core.NewOrderStore(s.Symbol)
|
||||||
s.orderStore.BindStream(session.UserDataStream)
|
s.orderStore.BindStream(session.UserDataStream)
|
||||||
|
|
||||||
if s.Position == nil {
|
if s.Position == nil {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/service"
|
"github.com/c9s/bbgo/pkg/service"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
@ -89,7 +90,7 @@ type Strategy struct {
|
||||||
ProfitStats *types.ProfitStats `persistence:"profit_stats"`
|
ProfitStats *types.ProfitStats `persistence:"profit_stats"`
|
||||||
|
|
||||||
// orderStore is used to store all the created orders, so that we can filter the trades.
|
// orderStore is used to store all the created orders, so that we can filter the trades.
|
||||||
orderStore *bbgo.OrderStore
|
orderStore *core.OrderStore
|
||||||
|
|
||||||
// activeOrders is the locally maintained active order book of the maker orders.
|
// activeOrders is the locally maintained active order book of the maker orders.
|
||||||
activeOrders *bbgo.ActiveOrderBook
|
activeOrders *bbgo.ActiveOrderBook
|
||||||
|
@ -562,7 +563,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
|
|
||||||
bbgo.Notify("grid %s position", s.Symbol, s.State.Position)
|
bbgo.Notify("grid %s position", s.Symbol, s.State.Position)
|
||||||
|
|
||||||
s.orderStore = bbgo.NewOrderStore(s.Symbol)
|
s.orderStore = core.NewOrderStore(s.Symbol)
|
||||||
s.orderStore.BindStream(session.UserDataStream)
|
s.orderStore.BindStream(session.UserDataStream)
|
||||||
|
|
||||||
// we don't persist orders so that we can not clear the previous orders for now. just need time to support this.
|
// we don't persist orders so that we can not clear the previous orders for now. just need time to support this.
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"go.uber.org/multierr"
|
"go.uber.org/multierr"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/exchange/retry"
|
"github.com/c9s/bbgo/pkg/exchange/retry"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
@ -186,7 +187,7 @@ type Strategy struct {
|
||||||
orderQueryService types.ExchangeOrderQueryService
|
orderQueryService types.ExchangeOrderQueryService
|
||||||
|
|
||||||
orderExecutor OrderExecutor
|
orderExecutor OrderExecutor
|
||||||
historicalTrades *bbgo.TradeStore
|
historicalTrades *core.TradeStore
|
||||||
|
|
||||||
logger *logrus.Entry
|
logger *logrus.Entry
|
||||||
|
|
||||||
|
@ -1858,7 +1859,7 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.historicalTrades = bbgo.NewTradeStore()
|
s.historicalTrades = core.NewTradeStore()
|
||||||
s.historicalTrades.EnablePrune = true
|
s.historicalTrades.EnablePrune = true
|
||||||
s.historicalTrades.BindStream(session.UserDataStream)
|
s.historicalTrades.BindStream(session.UserDataStream)
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
gridmocks "github.com/c9s/bbgo/pkg/strategy/grid2/mocks"
|
gridmocks "github.com/c9s/bbgo/pkg/strategy/grid2/mocks"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
@ -588,7 +588,7 @@ func newTestStrategy() *Strategy {
|
||||||
UpperPrice: number(20_000),
|
UpperPrice: number(20_000),
|
||||||
LowerPrice: number(10_000),
|
LowerPrice: number(10_000),
|
||||||
GridNum: 11,
|
GridNum: 11,
|
||||||
historicalTrades: bbgo.NewTradeStore(),
|
historicalTrades: core.NewTradeStore(),
|
||||||
|
|
||||||
filledOrderIDMap: types.NewSyncOrderMap(),
|
filledOrderIDMap: types.NewSyncOrderMap(),
|
||||||
|
|
||||||
|
|
|
@ -146,23 +146,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
|
|
||||||
if !s.PositionHardLimit.IsZero() && !s.MaxPositionQuantity.IsZero() {
|
if !s.PositionHardLimit.IsZero() && !s.MaxPositionQuantity.IsZero() {
|
||||||
log.Infof("positionHardLimit and maxPositionQuantity are configured, setting up PositionRiskControl...")
|
log.Infof("positionHardLimit and maxPositionQuantity are configured, setting up PositionRiskControl...")
|
||||||
s.positionRiskControl = riskcontrol.NewPositionRiskControl(s.PositionHardLimit, s.MaxPositionQuantity, s.orderExecutor.TradeCollector())
|
s.positionRiskControl = riskcontrol.NewPositionRiskControl(s.orderExecutor, s.PositionHardLimit, s.MaxPositionQuantity)
|
||||||
s.positionRiskControl.OnReleasePosition(func(quantity fixedpoint.Value, side types.SideType) {
|
|
||||||
createdOrders, err := s.orderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
|
||||||
Symbol: s.Symbol,
|
|
||||||
Market: s.Market,
|
|
||||||
Side: side,
|
|
||||||
Type: types.OrderTypeMarket,
|
|
||||||
Quantity: quantity,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Errorf("failed to submit orders")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("created position release orders: %+v", createdOrders)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !s.CircuitBreakLossThreshold.IsZero() {
|
if !s.CircuitBreakLossThreshold.IsZero() {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/util"
|
"github.com/c9s/bbgo/pkg/util"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -65,7 +66,7 @@ type Strategy struct {
|
||||||
|
|
||||||
activeAdjustmentOrders *bbgo.ActiveOrderBook
|
activeAdjustmentOrders *bbgo.ActiveOrderBook
|
||||||
activeWallOrders *bbgo.ActiveOrderBook
|
activeWallOrders *bbgo.ActiveOrderBook
|
||||||
orderStore *bbgo.OrderStore
|
orderStore *core.OrderStore
|
||||||
tradeCollector *bbgo.TradeCollector
|
tradeCollector *bbgo.TradeCollector
|
||||||
|
|
||||||
groupID uint32
|
groupID uint32
|
||||||
|
@ -273,7 +274,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
s.activeAdjustmentOrders = bbgo.NewActiveOrderBook(s.Symbol)
|
s.activeAdjustmentOrders = bbgo.NewActiveOrderBook(s.Symbol)
|
||||||
s.activeAdjustmentOrders.BindStream(session.UserDataStream)
|
s.activeAdjustmentOrders.BindStream(session.UserDataStream)
|
||||||
|
|
||||||
s.orderStore = bbgo.NewOrderStore(s.Symbol)
|
s.orderStore = core.NewOrderStore(s.Symbol)
|
||||||
s.orderStore.BindStream(session.UserDataStream)
|
s.orderStore.BindStream(session.UserDataStream)
|
||||||
|
|
||||||
s.tradeCollector = bbgo.NewTradeCollector(s.Symbol, s.Position, s.orderStore)
|
s.tradeCollector = bbgo.NewTradeCollector(s.Symbol, s.Position, s.orderStore)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
@ -50,7 +51,7 @@ type Strategy struct {
|
||||||
sessions map[string]*bbgo.ExchangeSession
|
sessions map[string]*bbgo.ExchangeSession
|
||||||
orderBooks map[string]*bbgo.ActiveOrderBook
|
orderBooks map[string]*bbgo.ActiveOrderBook
|
||||||
|
|
||||||
orderStore *bbgo.OrderStore
|
orderStore *core.OrderStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) ID() string {
|
func (s *Strategy) ID() string {
|
||||||
|
@ -242,7 +243,7 @@ func (s *Strategy) CrossRun(ctx context.Context, _ bbgo.OrderExecutionRouter, se
|
||||||
s.sessions = make(map[string]*bbgo.ExchangeSession)
|
s.sessions = make(map[string]*bbgo.ExchangeSession)
|
||||||
s.orderBooks = make(map[string]*bbgo.ActiveOrderBook)
|
s.orderBooks = make(map[string]*bbgo.ActiveOrderBook)
|
||||||
|
|
||||||
s.orderStore = bbgo.NewOrderStore("")
|
s.orderStore = core.NewOrderStore("")
|
||||||
|
|
||||||
for _, sessionName := range s.PreferredSessions {
|
for _, sessionName := range s.PreferredSessions {
|
||||||
session, ok := sessions[sessionName]
|
session, ok := sessions[sessionName]
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
"github.com/c9s/bbgo/pkg/core"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/indicator"
|
"github.com/c9s/bbgo/pkg/indicator"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
@ -103,7 +104,7 @@ type Strategy struct {
|
||||||
hedgeErrorLimiter *rate.Limiter
|
hedgeErrorLimiter *rate.Limiter
|
||||||
hedgeErrorRateReservation *rate.Reservation
|
hedgeErrorRateReservation *rate.Reservation
|
||||||
|
|
||||||
orderStore *bbgo.OrderStore
|
orderStore *core.OrderStore
|
||||||
tradeCollector *bbgo.TradeCollector
|
tradeCollector *bbgo.TradeCollector
|
||||||
|
|
||||||
askPriceHeartBeat, bidPriceHeartBeat types.PriceHeartBeat
|
askPriceHeartBeat, bidPriceHeartBeat types.PriceHeartBeat
|
||||||
|
@ -732,7 +733,7 @@ func (s *Strategy) CrossRun(ctx context.Context, orderExecutionRouter bbgo.Order
|
||||||
s.activeMakerOrders = bbgo.NewActiveOrderBook(s.Symbol)
|
s.activeMakerOrders = bbgo.NewActiveOrderBook(s.Symbol)
|
||||||
s.activeMakerOrders.BindStream(s.makerSession.UserDataStream)
|
s.activeMakerOrders.BindStream(s.makerSession.UserDataStream)
|
||||||
|
|
||||||
s.orderStore = bbgo.NewOrderStore(s.Symbol)
|
s.orderStore = core.NewOrderStore(s.Symbol)
|
||||||
s.orderStore.BindStream(s.sourceSession.UserDataStream)
|
s.orderStore.BindStream(s.sourceSession.UserDataStream)
|
||||||
s.orderStore.BindStream(s.makerSession.UserDataStream)
|
s.orderStore.BindStream(s.makerSession.UserDataStream)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user