mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 06:53:52 +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
|
||||
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:
|
||||
|
||||
- on: binance
|
||||
|
|
|
@ -12,6 +12,13 @@ sessions:
|
|||
envVarPrefix: binance
|
||||
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:
|
||||
|
||||
- on: binance
|
||||
|
|
|
@ -82,16 +82,25 @@ func TestLoadConfig(t *testing.T) {
|
|||
assert.Equal(t, map[string]interface{}{
|
||||
"sessions": map[string]interface{}{
|
||||
"max": map[string]interface{}{
|
||||
"exchange": "max",
|
||||
"envVarPrefix": "MAX",
|
||||
"takerFeeRate": 0.,
|
||||
"makerFeeRate": 0.,
|
||||
"exchange": "max",
|
||||
"envVarPrefix": "MAX",
|
||||
"takerFeeRate": 0.,
|
||||
"makerFeeRate": 0.,
|
||||
"modifyOrderAmountForFee": false,
|
||||
},
|
||||
"binance": map[string]interface{}{
|
||||
"exchange": "binance",
|
||||
"envVarPrefix": "BINANCE",
|
||||
"takerFeeRate": 0.,
|
||||
"makerFeeRate": 0.,
|
||||
"exchange": "binance",
|
||||
"envVarPrefix": "BINANCE",
|
||||
"takerFeeRate": 0.,
|
||||
"makerFeeRate": 0.,
|
||||
"modifyOrderAmountForFee": false,
|
||||
},
|
||||
"ftx": map[string]interface{}{
|
||||
"exchange": "ftx",
|
||||
"envVarPrefix": "FTX",
|
||||
"takerFeeRate": 0.,
|
||||
"makerFeeRate": 0.,
|
||||
"modifyOrderAmountForFee": true,
|
||||
},
|
||||
},
|
||||
"build": map[string]interface{}{
|
||||
|
|
|
@ -39,9 +39,10 @@ type ExchangeSession struct {
|
|||
SubAccount string `json:"subAccount,omitempty" yaml:"subAccount,omitempty"`
|
||||
|
||||
// Withdrawal is used for enabling withdrawal functions
|
||||
Withdrawal bool `json:"withdrawal,omitempty" yaml:"withdrawal,omitempty"`
|
||||
MakerFeeRate fixedpoint.Value `json:"makerFeeRate" yaml:"makerFeeRate"`
|
||||
TakerFeeRate fixedpoint.Value `json:"takerFeeRate" yaml:"takerFeeRate"`
|
||||
Withdrawal bool `json:"withdrawal,omitempty" yaml:"withdrawal,omitempty"`
|
||||
MakerFeeRate fixedpoint.Value `json:"makerFeeRate" yaml:"makerFeeRate"`
|
||||
TakerFeeRate fixedpoint.Value `json:"takerFeeRate" yaml:"takerFeeRate"`
|
||||
ModifyOrderAmountForFee bool `json:"modifyOrderAmountForFee" yaml:"modifyOrderAmountForFee"`
|
||||
|
||||
PublicOnly bool `json:"publicOnly,omitempty" yaml:"publicOnly"`
|
||||
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 {
|
||||
session.MarketDataStream = &types.HeikinAshiStream{
|
||||
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
|
||||
takerFeeRate: 0
|
||||
makerFeeRate: 0
|
||||
modifyOrderAmountForFee: false
|
||||
binance:
|
||||
exchange: binance
|
||||
envVarPrefix: BINANCE
|
||||
takerFeeRate: 0
|
||||
makerFeeRate: 0
|
||||
modifyOrderAmountForFee: false
|
||||
ftx:
|
||||
exchange: ftx
|
||||
envVarPrefix: FTX
|
||||
takerFeeRate: 0
|
||||
makerFeeRate: 0
|
||||
modifyOrderAmountForFee: true
|
||||
|
||||
exchangeStrategies:
|
||||
- on: ["binance"]
|
||||
|
|
|
@ -37,9 +37,10 @@ var marketDataLimiter = rate.NewLimiter(rate.Every(500*time.Millisecond), 2)
|
|||
type Exchange struct {
|
||||
client *ftxapi.RestClient
|
||||
|
||||
key, secret string
|
||||
subAccount string
|
||||
restEndpoint *url.URL
|
||||
key, secret string
|
||||
subAccount string
|
||||
restEndpoint *url.URL
|
||||
orderAmountReduceFactor fixedpoint.Value
|
||||
}
|
||||
|
||||
type MarketTicker struct {
|
||||
|
@ -91,8 +92,9 @@ func NewExchange(key, secret string, subAccount string) *Exchange {
|
|||
restEndpoint: u,
|
||||
key: key,
|
||||
// pragma: allowlist nextline secret
|
||||
secret: secret,
|
||||
subAccount: subAccount,
|
||||
secret: secret,
|
||||
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
|
||||
// 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{
|
||||
|
@ -406,11 +415,17 @@ func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder
|
|||
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.Market(toLocalSymbol(TrimUpperString(so.Symbol)))
|
||||
req.OrderType(orderType)
|
||||
req.Side(ftxapi.Side(TrimLowerString(string(so.Side))))
|
||||
req.Size(so.Quantity)
|
||||
req.Size(submitQuantity)
|
||||
|
||||
switch so.Type {
|
||||
case types.OrderTypeLimit, types.OrderTypeLimitMaker:
|
||||
|
|
|
@ -107,6 +107,10 @@ type ExchangeDefaultFeeRates interface {
|
|||
DefaultFeeRates() ExchangeFee
|
||||
}
|
||||
|
||||
type ExchangeAmountFeeProtect interface {
|
||||
SetModifyOrderAmountForFee(ExchangeFee)
|
||||
}
|
||||
|
||||
type ExchangeTradeHistoryService interface {
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue
Block a user