mirror of
https://github.com/c9s/bbgo.git
synced 2024-09-20 08:11:08 +00:00
Merge pull request #860 from COLDTURNIP/feature/exchange_order_amount_protection
exchange: order fee-amount protection
This commit is contained in:
commit
ed975b7ed9
|
@ -12,6 +12,13 @@ sessions:
|
||||||
envVarPrefix: binance
|
envVarPrefix: binance
|
||||||
heikinAshi: false
|
heikinAshi: false
|
||||||
|
|
||||||
|
# Drift strategy intends to place buy/sell orders as much value mas it could be. To exchanges that requires to
|
||||||
|
# calculate fees before placing limit orders (e.g. FTX Pro), make sure the fee rate is configured correctly and
|
||||||
|
# enable modifyOrderAmountForFee to prevent order rejection.
|
||||||
|
makerFeeRate: 0.0002
|
||||||
|
takerFeeRate: 0.0007
|
||||||
|
modifyOrderAmountForFee: false
|
||||||
|
|
||||||
exchangeStrategies:
|
exchangeStrategies:
|
||||||
|
|
||||||
- on: binance
|
- on: binance
|
||||||
|
|
|
@ -12,6 +12,13 @@ sessions:
|
||||||
envVarPrefix: binance
|
envVarPrefix: binance
|
||||||
heikinAshi: false
|
heikinAshi: false
|
||||||
|
|
||||||
|
# Drift strategy intends to place buy/sell orders as much value mas it could be. To exchanges that requires to
|
||||||
|
# calculate fees before placing limit orders (e.g. FTX Pro), make sure the fee rate is configured correctly and
|
||||||
|
# enable modifyOrderAmountForFee to prevent order rejection.
|
||||||
|
makerFeeRate: 0.0002
|
||||||
|
takerFeeRate: 0.0007
|
||||||
|
modifyOrderAmountForFee: false
|
||||||
|
|
||||||
exchangeStrategies:
|
exchangeStrategies:
|
||||||
|
|
||||||
- on: binance
|
- on: binance
|
||||||
|
|
|
@ -86,12 +86,21 @@ func TestLoadConfig(t *testing.T) {
|
||||||
"envVarPrefix": "MAX",
|
"envVarPrefix": "MAX",
|
||||||
"takerFeeRate": 0.,
|
"takerFeeRate": 0.,
|
||||||
"makerFeeRate": 0.,
|
"makerFeeRate": 0.,
|
||||||
|
"modifyOrderAmountForFee": false,
|
||||||
},
|
},
|
||||||
"binance": map[string]interface{}{
|
"binance": map[string]interface{}{
|
||||||
"exchange": "binance",
|
"exchange": "binance",
|
||||||
"envVarPrefix": "BINANCE",
|
"envVarPrefix": "BINANCE",
|
||||||
"takerFeeRate": 0.,
|
"takerFeeRate": 0.,
|
||||||
"makerFeeRate": 0.,
|
"makerFeeRate": 0.,
|
||||||
|
"modifyOrderAmountForFee": false,
|
||||||
|
},
|
||||||
|
"ftx": map[string]interface{}{
|
||||||
|
"exchange": "ftx",
|
||||||
|
"envVarPrefix": "FTX",
|
||||||
|
"takerFeeRate": 0.,
|
||||||
|
"makerFeeRate": 0.,
|
||||||
|
"modifyOrderAmountForFee": true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"build": map[string]interface{}{
|
"build": map[string]interface{}{
|
||||||
|
|
|
@ -42,6 +42,7 @@ type ExchangeSession struct {
|
||||||
Withdrawal bool `json:"withdrawal,omitempty" yaml:"withdrawal,omitempty"`
|
Withdrawal bool `json:"withdrawal,omitempty" yaml:"withdrawal,omitempty"`
|
||||||
MakerFeeRate fixedpoint.Value `json:"makerFeeRate" yaml:"makerFeeRate"`
|
MakerFeeRate fixedpoint.Value `json:"makerFeeRate" yaml:"makerFeeRate"`
|
||||||
TakerFeeRate fixedpoint.Value `json:"takerFeeRate" yaml:"takerFeeRate"`
|
TakerFeeRate fixedpoint.Value `json:"takerFeeRate" yaml:"takerFeeRate"`
|
||||||
|
ModifyOrderAmountForFee bool `json:"modifyOrderAmountForFee" yaml:"modifyOrderAmountForFee"`
|
||||||
|
|
||||||
PublicOnly bool `json:"publicOnly,omitempty" yaml:"publicOnly"`
|
PublicOnly bool `json:"publicOnly,omitempty" yaml:"publicOnly"`
|
||||||
Margin bool `json:"margin,omitempty" yaml:"margin"`
|
Margin bool `json:"margin,omitempty" yaml:"margin"`
|
||||||
|
@ -202,6 +203,16 @@ func (session *ExchangeSession) Init(ctx context.Context, environ *Environment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if session.ModifyOrderAmountForFee {
|
||||||
|
amountProtectExchange, ok := session.Exchange.(types.ExchangeAmountFeeProtect)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("exchange %s does not support order amount protection", session.ExchangeName.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
fees := types.ExchangeFee{MakerFeeRate: session.MakerFeeRate, TakerFeeRate: session.TakerFeeRate}
|
||||||
|
amountProtectExchange.SetModifyOrderAmountForFee(fees)
|
||||||
|
}
|
||||||
|
|
||||||
if session.UseHeikinAshi {
|
if session.UseHeikinAshi {
|
||||||
session.MarketDataStream = &types.HeikinAshiStream{
|
session.MarketDataStream = &types.HeikinAshiStream{
|
||||||
StandardStreamEmitter: session.MarketDataStream.(types.StandardStreamEmitter),
|
StandardStreamEmitter: session.MarketDataStream.(types.StandardStreamEmitter),
|
||||||
|
|
8
pkg/bbgo/testdata/strategy.yaml
vendored
8
pkg/bbgo/testdata/strategy.yaml
vendored
|
@ -5,11 +5,19 @@ sessions:
|
||||||
envVarPrefix: MAX
|
envVarPrefix: MAX
|
||||||
takerFeeRate: 0
|
takerFeeRate: 0
|
||||||
makerFeeRate: 0
|
makerFeeRate: 0
|
||||||
|
modifyOrderAmountForFee: false
|
||||||
binance:
|
binance:
|
||||||
exchange: binance
|
exchange: binance
|
||||||
envVarPrefix: BINANCE
|
envVarPrefix: BINANCE
|
||||||
takerFeeRate: 0
|
takerFeeRate: 0
|
||||||
makerFeeRate: 0
|
makerFeeRate: 0
|
||||||
|
modifyOrderAmountForFee: false
|
||||||
|
ftx:
|
||||||
|
exchange: ftx
|
||||||
|
envVarPrefix: FTX
|
||||||
|
takerFeeRate: 0
|
||||||
|
makerFeeRate: 0
|
||||||
|
modifyOrderAmountForFee: true
|
||||||
|
|
||||||
exchangeStrategies:
|
exchangeStrategies:
|
||||||
- on: ["binance"]
|
- on: ["binance"]
|
||||||
|
|
|
@ -40,6 +40,7 @@ type Exchange struct {
|
||||||
key, secret string
|
key, secret string
|
||||||
subAccount string
|
subAccount string
|
||||||
restEndpoint *url.URL
|
restEndpoint *url.URL
|
||||||
|
orderAmountReduceFactor fixedpoint.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
type MarketTicker struct {
|
type MarketTicker struct {
|
||||||
|
@ -93,6 +94,7 @@ func NewExchange(key, secret string, subAccount string) *Exchange {
|
||||||
// pragma: allowlist nextline secret
|
// pragma: allowlist nextline secret
|
||||||
secret: secret,
|
secret: secret,
|
||||||
subAccount: subAccount,
|
subAccount: subAccount,
|
||||||
|
orderAmountReduceFactor: fixedpoint.One,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,6 +223,13 @@ func (e *Exchange) DefaultFeeRates() types.ExchangeFee {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetModifyOrderAmountForFee protects the limit buy orders by reducing amount with taker fee.
|
||||||
|
// The amount is recalculated before submit: submit_amount = original_amount / (1 + taker_fee_rate) .
|
||||||
|
// This prevents balance exceeding error while closing position without spot margin enabled.
|
||||||
|
func (e *Exchange) SetModifyOrderAmountForFee(feeRate types.ExchangeFee) {
|
||||||
|
e.orderAmountReduceFactor = fixedpoint.One.Add(feeRate.TakerFeeRate)
|
||||||
|
}
|
||||||
|
|
||||||
// resolution field in api
|
// resolution field in api
|
||||||
// window length in seconds. options: 15, 60, 300, 900, 3600, 14400, 86400, or any multiple of 86400 up to 30*86400
|
// window length in seconds. options: 15, 60, 300, 900, 3600, 14400, 86400, or any multiple of 86400 up to 30*86400
|
||||||
var supportedIntervals = map[types.Interval]int{
|
var supportedIntervals = map[types.Interval]int{
|
||||||
|
@ -406,11 +415,17 @@ func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder
|
||||||
logrus.WithError(err).Error("type error")
|
logrus.WithError(err).Error("type error")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
submitQuantity := so.Quantity
|
||||||
|
switch orderType {
|
||||||
|
case ftxapi.OrderTypeLimit, ftxapi.OrderTypeStopLimit:
|
||||||
|
submitQuantity = so.Quantity.Div(e.orderAmountReduceFactor)
|
||||||
|
}
|
||||||
|
|
||||||
req := e.client.NewPlaceOrderRequest()
|
req := e.client.NewPlaceOrderRequest()
|
||||||
req.Market(toLocalSymbol(TrimUpperString(so.Symbol)))
|
req.Market(toLocalSymbol(TrimUpperString(so.Symbol)))
|
||||||
req.OrderType(orderType)
|
req.OrderType(orderType)
|
||||||
req.Side(ftxapi.Side(TrimLowerString(string(so.Side))))
|
req.Side(ftxapi.Side(TrimLowerString(string(so.Side))))
|
||||||
req.Size(so.Quantity)
|
req.Size(submitQuantity)
|
||||||
|
|
||||||
switch so.Type {
|
switch so.Type {
|
||||||
case types.OrderTypeLimit, types.OrderTypeLimitMaker:
|
case types.OrderTypeLimit, types.OrderTypeLimitMaker:
|
||||||
|
|
|
@ -107,6 +107,10 @@ type ExchangeDefaultFeeRates interface {
|
||||||
DefaultFeeRates() ExchangeFee
|
DefaultFeeRates() ExchangeFee
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ExchangeAmountFeeProtect interface {
|
||||||
|
SetModifyOrderAmountForFee(ExchangeFee)
|
||||||
|
}
|
||||||
|
|
||||||
type ExchangeTradeHistoryService interface {
|
type ExchangeTradeHistoryService interface {
|
||||||
QueryTrades(ctx context.Context, symbol string, options *TradeQueryOptions) ([]Trade, error)
|
QueryTrades(ctx context.Context, symbol string, options *TradeQueryOptions) ([]Trade, error)
|
||||||
QueryClosedOrders(ctx context.Context, symbol string, since, until time.Time, lastOrderID uint64) (orders []Order, err error)
|
QueryClosedOrders(ctx context.Context, symbol string, since, until time.Time, lastOrderID uint64) (orders []Order, err error)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user