mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
xfunding: move position state to state struct
This commit is contained in:
parent
108bb5deeb
commit
c1fbbbe400
|
@ -1,25 +0,0 @@
|
||||||
// Code generated by "stringer -type=PositionAction"; DO NOT EDIT.
|
|
||||||
|
|
||||||
package xfunding
|
|
||||||
|
|
||||||
import "strconv"
|
|
||||||
|
|
||||||
func _() {
|
|
||||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
|
||||||
// Re-run the stringer command to generate them again.
|
|
||||||
var x [1]struct{}
|
|
||||||
_ = x[PositionNoOp-0]
|
|
||||||
_ = x[PositionOpening-1]
|
|
||||||
_ = x[PositionClosing-2]
|
|
||||||
}
|
|
||||||
|
|
||||||
const _PositionAction_name = "PositionNoOpPositionOpeningPositionClosing"
|
|
||||||
|
|
||||||
var _PositionAction_index = [...]uint8{0, 12, 27, 42}
|
|
||||||
|
|
||||||
func (i PositionAction) String() string {
|
|
||||||
if i < 0 || i >= PositionAction(len(_PositionAction_index)-1) {
|
|
||||||
return "PositionAction(" + strconv.FormatInt(int64(i), 10) + ")"
|
|
||||||
}
|
|
||||||
return _PositionAction_name[_PositionAction_index[i]:_PositionAction_index[i+1]]
|
|
||||||
}
|
|
25
pkg/strategy/xfunding/positionstate_string.go
Normal file
25
pkg/strategy/xfunding/positionstate_string.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// Code generated by "stringer -type=PositionState"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package xfunding
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[PositionNoOp-0]
|
||||||
|
_ = x[PositionOpening-1]
|
||||||
|
_ = x[PositionClosing-2]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _PositionState_name = "PositionNoOpPositionOpeningPositionClosing"
|
||||||
|
|
||||||
|
var _PositionState_index = [...]uint8{0, 12, 27, 42}
|
||||||
|
|
||||||
|
func (i PositionState) String() string {
|
||||||
|
if i < 0 || i >= PositionState(len(_PositionState_index)-1) {
|
||||||
|
return "PositionState(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _PositionState_name[_PositionState_index[i]:_PositionState_index[i+1]]
|
||||||
|
}
|
|
@ -20,11 +20,15 @@ import (
|
||||||
|
|
||||||
const ID = "xfunding"
|
const ID = "xfunding"
|
||||||
|
|
||||||
//go:generate stringer -type=PositionAction
|
// Position State Transitions:
|
||||||
type PositionAction int
|
// NoOp -> Opening | Closing
|
||||||
|
// Opening -> NoOp -> Closing
|
||||||
|
// Closing -> NoOp -> Opening
|
||||||
|
//go:generate stringer -type=PositionState
|
||||||
|
type PositionState int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PositionNoOp PositionAction = iota
|
PositionNoOp PositionState = iota
|
||||||
PositionOpening
|
PositionOpening
|
||||||
PositionClosing
|
PositionClosing
|
||||||
)
|
)
|
||||||
|
@ -104,16 +108,17 @@ type Strategy struct {
|
||||||
spotOrderExecutor, futuresOrderExecutor *bbgo.GeneralOrderExecutor
|
spotOrderExecutor, futuresOrderExecutor *bbgo.GeneralOrderExecutor
|
||||||
spotMarket, futuresMarket types.Market
|
spotMarket, futuresMarket types.Market
|
||||||
|
|
||||||
// positionAction is default to NoOp
|
|
||||||
positionAction PositionAction
|
|
||||||
|
|
||||||
// positionType is the futures position type
|
// positionType is the futures position type
|
||||||
// currently we only support short position for the positive funding rate
|
// currently we only support short position for the positive funding rate
|
||||||
positionType types.PositionType
|
positionType types.PositionType
|
||||||
}
|
}
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
PositionStartTime time.Time `json:"positionStartTime"`
|
PositionStartTime time.Time `json:"positionStartTime"`
|
||||||
|
|
||||||
|
// PositionState is default to NoOp
|
||||||
|
PositionState PositionState
|
||||||
|
|
||||||
PendingBaseTransfer fixedpoint.Value `json:"pendingBaseTransfer"`
|
PendingBaseTransfer fixedpoint.Value `json:"pendingBaseTransfer"`
|
||||||
TotalBaseTransfer fixedpoint.Value `json:"totalBaseTransfer"`
|
TotalBaseTransfer fixedpoint.Value `json:"totalBaseTransfer"`
|
||||||
UsedQuoteInvestment fixedpoint.Value `json:"usedQuoteInvestment"`
|
UsedQuoteInvestment fixedpoint.Value `json:"usedQuoteInvestment"`
|
||||||
|
@ -252,6 +257,7 @@ func (s *Strategy) CrossRun(ctx context.Context, orderExecutionRouter bbgo.Order
|
||||||
|
|
||||||
if s.State == nil {
|
if s.State == nil {
|
||||||
s.State = &State{
|
s.State = &State{
|
||||||
|
PositionState: PositionNoOp,
|
||||||
PendingBaseTransfer: fixedpoint.Zero,
|
PendingBaseTransfer: fixedpoint.Zero,
|
||||||
TotalBaseTransfer: fixedpoint.Zero,
|
TotalBaseTransfer: fixedpoint.Zero,
|
||||||
UsedQuoteInvestment: fixedpoint.Zero,
|
UsedQuoteInvestment: fixedpoint.Zero,
|
||||||
|
@ -277,7 +283,7 @@ func (s *Strategy) CrossRun(ctx context.Context, orderExecutionRouter bbgo.Order
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch s.positionAction {
|
switch s.State.PositionState {
|
||||||
case PositionOpening:
|
case PositionOpening:
|
||||||
if trade.Side != types.SideTypeBuy {
|
if trade.Side != types.SideTypeBuy {
|
||||||
log.Errorf("unexpected trade side: %+v, expecting BUY trade", trade)
|
log.Errorf("unexpected trade side: %+v, expecting BUY trade", trade)
|
||||||
|
@ -289,7 +295,7 @@ func (s *Strategy) CrossRun(ctx context.Context, orderExecutionRouter bbgo.Order
|
||||||
|
|
||||||
s.State.UsedQuoteInvestment = s.State.UsedQuoteInvestment.Add(trade.QuoteQuantity)
|
s.State.UsedQuoteInvestment = s.State.UsedQuoteInvestment.Add(trade.QuoteQuantity)
|
||||||
if s.State.UsedQuoteInvestment.Compare(s.QuoteInvestment) >= 0 {
|
if s.State.UsedQuoteInvestment.Compare(s.QuoteInvestment) >= 0 {
|
||||||
s.positionAction = PositionNoOp
|
s.State.PositionState = PositionNoOp
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have trade, try to query the balance and transfer the balance to the futures wallet account
|
// if we have trade, try to query the balance and transfer the balance to the futures wallet account
|
||||||
|
@ -316,7 +322,7 @@ func (s *Strategy) CrossRun(ctx context.Context, orderExecutionRouter bbgo.Order
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch s.positionAction {
|
switch s.State.PositionState {
|
||||||
case PositionClosing:
|
case PositionClosing:
|
||||||
if err := backoff.RetryGeneral(ctx, func() error {
|
if err := backoff.RetryGeneral(ctx, func() error {
|
||||||
return s.transferOut(ctx, binanceSpot, s.spotMarket.BaseCurrency, trade)
|
return s.transferOut(ctx, binanceSpot, s.spotMarket.BaseCurrency, trade)
|
||||||
|
@ -367,13 +373,13 @@ func (s *Strategy) queryAndDetectPremiumIndex(ctx context.Context, binanceFuture
|
||||||
log.Infof("premiumIndex: %+v", premiumIndex)
|
log.Infof("premiumIndex: %+v", premiumIndex)
|
||||||
|
|
||||||
if changed := s.detectPremiumIndex(premiumIndex); changed {
|
if changed := s.detectPremiumIndex(premiumIndex); changed {
|
||||||
log.Infof("position action: %s %s", s.positionType, s.positionAction.String())
|
log.Infof("position action: %s %s", s.positionType, s.State.PositionState.String())
|
||||||
s.triggerPositionAction(ctx)
|
s.triggerPositionAction(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) triggerPositionAction(ctx context.Context) {
|
func (s *Strategy) triggerPositionAction(ctx context.Context) {
|
||||||
switch s.positionAction {
|
switch s.State.PositionState {
|
||||||
case PositionOpening:
|
case PositionOpening:
|
||||||
s.increaseSpotPosition(ctx)
|
s.increaseSpotPosition(ctx)
|
||||||
s.syncFuturesPosition(ctx)
|
s.syncFuturesPosition(ctx)
|
||||||
|
@ -384,7 +390,7 @@ func (s *Strategy) triggerPositionAction(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) reduceFuturesPosition(ctx context.Context) {
|
func (s *Strategy) reduceFuturesPosition(ctx context.Context) {
|
||||||
switch s.positionAction {
|
switch s.State.PositionState {
|
||||||
case PositionOpening, PositionNoOp:
|
case PositionOpening, PositionNoOp:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -443,7 +449,7 @@ func (s *Strategy) syncFuturesPosition(ctx context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch s.positionAction {
|
switch s.State.PositionState {
|
||||||
case PositionClosing:
|
case PositionClosing:
|
||||||
return
|
return
|
||||||
case PositionOpening, PositionNoOp:
|
case PositionOpening, PositionNoOp:
|
||||||
|
@ -532,7 +538,8 @@ func (s *Strategy) increaseSpotPosition(ctx context.Context) {
|
||||||
log.Errorf("funding long position type is not supported")
|
log.Errorf("funding long position type is not supported")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.positionAction != PositionOpening {
|
|
||||||
|
if s.State.PositionState != PositionOpening {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,6 +547,8 @@ func (s *Strategy) increaseSpotPosition(ctx context.Context) {
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
if s.State.UsedQuoteInvestment.Compare(s.QuoteInvestment) >= 0 {
|
if s.State.UsedQuoteInvestment.Compare(s.QuoteInvestment) >= 0 {
|
||||||
|
// stop increase the position
|
||||||
|
s.State.PositionState = PositionNoOp
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,6 +595,10 @@ func (s *Strategy) increaseSpotPosition(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) detectPremiumIndex(premiumIndex *types.PremiumIndex) (changed bool) {
|
func (s *Strategy) detectPremiumIndex(premiumIndex *types.PremiumIndex) (changed bool) {
|
||||||
|
if s.State.PositionState != PositionNoOp {
|
||||||
|
return changed
|
||||||
|
}
|
||||||
|
|
||||||
fundingRate := premiumIndex.LastFundingRate
|
fundingRate := premiumIndex.LastFundingRate
|
||||||
|
|
||||||
log.Infof("last %s funding rate: %s", s.Symbol, fundingRate.Percentage())
|
log.Infof("last %s funding rate: %s", s.Symbol, fundingRate.Percentage())
|
||||||
|
@ -620,11 +633,12 @@ func (s *Strategy) detectPremiumIndex(premiumIndex *types.PremiumIndex) (changed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) startOpeningPosition(pt types.PositionType, t time.Time) {
|
func (s *Strategy) startOpeningPosition(pt types.PositionType, t time.Time) {
|
||||||
if s.positionAction == PositionOpening {
|
// we should only open a new position when there is no op on the position
|
||||||
|
if s.State.PositionState != PositionNoOp {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.positionAction = PositionOpening
|
s.State.PositionState = PositionOpening
|
||||||
s.positionType = pt
|
s.positionType = pt
|
||||||
|
|
||||||
// reset the transfer stats
|
// reset the transfer stats
|
||||||
|
@ -634,11 +648,11 @@ func (s *Strategy) startOpeningPosition(pt types.PositionType, t time.Time) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) startClosingPosition() {
|
func (s *Strategy) startClosingPosition() {
|
||||||
if s.positionAction == PositionClosing {
|
if s.State.PositionState != PositionNoOp {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.positionAction = PositionClosing
|
s.State.PositionState = PositionClosing
|
||||||
|
|
||||||
// reset the transfer stats
|
// reset the transfer stats
|
||||||
s.State.PendingBaseTransfer = fixedpoint.Zero
|
s.State.PendingBaseTransfer = fixedpoint.Zero
|
||||||
|
|
Loading…
Reference in New Issue
Block a user