mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
liquiditymaker: use order generator
This commit is contained in:
parent
533907894e
commit
cc5c033af7
54
config/liquiditymaker.yaml
Normal file
54
config/liquiditymaker.yaml
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
sessions:
|
||||||
|
max:
|
||||||
|
exchange: max
|
||||||
|
envVarPrefix: max
|
||||||
|
makerFeeRate: 0%
|
||||||
|
takerFeeRate: 0.025%
|
||||||
|
|
||||||
|
#services:
|
||||||
|
# googleSpreadSheet:
|
||||||
|
# jsonTokenFile: ".credentials/google-cloud/service-account-json-token.json"
|
||||||
|
# spreadSheetId: "YOUR_SPREADSHEET_ID"
|
||||||
|
|
||||||
|
exchangeStrategies:
|
||||||
|
- on: max
|
||||||
|
liquiditymaker:
|
||||||
|
symbol: &symbol USDTTWD
|
||||||
|
|
||||||
|
## adjustmentUpdateInterval is the interval for adjusting position
|
||||||
|
adjustmentUpdateInterval: 1m
|
||||||
|
|
||||||
|
## liquidityUpdateInterval is the interval for updating liquidity orders
|
||||||
|
liquidityUpdateInterval: 1h
|
||||||
|
|
||||||
|
numOfLiquidityLayers: 30
|
||||||
|
askLiquidityAmount: 20_000.0
|
||||||
|
bidLiquidityAmount: 20_000.0
|
||||||
|
liquidityPriceRange: 2%
|
||||||
|
useLastTradePrice: true
|
||||||
|
spread: 1.1%
|
||||||
|
|
||||||
|
liquidityScale:
|
||||||
|
exp:
|
||||||
|
domain: [1, 30]
|
||||||
|
range: [1, 4]
|
||||||
|
|
||||||
|
## maxExposure controls how much balance should be used for placing the maker orders
|
||||||
|
maxExposure: 200_000
|
||||||
|
minProfit: 0.01%
|
||||||
|
|
||||||
|
|
||||||
|
backtest:
|
||||||
|
sessions:
|
||||||
|
- max
|
||||||
|
startTime: "2023-05-20"
|
||||||
|
endTime: "2023-06-01"
|
||||||
|
symbols:
|
||||||
|
- *symbol
|
||||||
|
account:
|
||||||
|
max:
|
||||||
|
makerFeeRate: 0.0%
|
||||||
|
takerFeeRate: 0.025%
|
||||||
|
balances:
|
||||||
|
USDT: 5000
|
||||||
|
TWD: 150_000
|
|
@ -25,6 +25,7 @@ import (
|
||||||
_ "github.com/c9s/bbgo/pkg/strategy/irr"
|
_ "github.com/c9s/bbgo/pkg/strategy/irr"
|
||||||
_ "github.com/c9s/bbgo/pkg/strategy/kline"
|
_ "github.com/c9s/bbgo/pkg/strategy/kline"
|
||||||
_ "github.com/c9s/bbgo/pkg/strategy/linregmaker"
|
_ "github.com/c9s/bbgo/pkg/strategy/linregmaker"
|
||||||
|
_ "github.com/c9s/bbgo/pkg/strategy/liquiditymaker"
|
||||||
_ "github.com/c9s/bbgo/pkg/strategy/marketcap"
|
_ "github.com/c9s/bbgo/pkg/strategy/marketcap"
|
||||||
_ "github.com/c9s/bbgo/pkg/strategy/pivotshort"
|
_ "github.com/c9s/bbgo/pkg/strategy/pivotshort"
|
||||||
_ "github.com/c9s/bbgo/pkg/strategy/pricealert"
|
_ "github.com/c9s/bbgo/pkg/strategy/pricealert"
|
||||||
|
|
|
@ -42,7 +42,7 @@ func TestLiquidityOrderGenerator(t *testing.T) {
|
||||||
assert.InDelta(t, 1.0, scale.Call(1.0), 0.00001)
|
assert.InDelta(t, 1.0, scale.Call(1.0), 0.00001)
|
||||||
assert.InDelta(t, 4.0, scale.Call(30.0), 0.00001)
|
assert.InDelta(t, 4.0, scale.Call(30.0), 0.00001)
|
||||||
|
|
||||||
totalAmount := Number(200_000.0)
|
totalAmount := Number(20_000.0)
|
||||||
|
|
||||||
t.Run("ask orders", func(t *testing.T) {
|
t.Run("ask orders", func(t *testing.T) {
|
||||||
orders := g.Generate(types.SideTypeSell, totalAmount, Number(2.0), Number(2.04), 30, scale)
|
orders := g.Generate(types.SideTypeSell, totalAmount, Number(2.0), Number(2.04), 30, scale)
|
||||||
|
@ -55,26 +55,26 @@ func TestLiquidityOrderGenerator(t *testing.T) {
|
||||||
assert.InDelta(t, totalAmount.Float64(), totalQuoteQuantity.Float64(), 1.0)
|
assert.InDelta(t, totalAmount.Float64(), totalQuoteQuantity.Float64(), 1.0)
|
||||||
|
|
||||||
AssertOrdersPriceSideQuantity(t, []PriceSideQuantityAssert{
|
AssertOrdersPriceSideQuantity(t, []PriceSideQuantityAssert{
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0000"), Quantity: Number("1513.40")},
|
{Side: types.SideTypeSell, Price: Number("2.0000"), Quantity: Number("151.34")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0013"), Quantity: Number("1587.50")},
|
{Side: types.SideTypeSell, Price: Number("2.0013"), Quantity: Number("158.75")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0027"), Quantity: Number("1665.23")},
|
{Side: types.SideTypeSell, Price: Number("2.0027"), Quantity: Number("166.52")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0041"), Quantity: Number("1746.77")},
|
{Side: types.SideTypeSell, Price: Number("2.0041"), Quantity: Number("174.67")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0055"), Quantity: Number("1832.30")},
|
{Side: types.SideTypeSell, Price: Number("2.0055"), Quantity: Number("183.23")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0068"), Quantity: Number("1922.02")},
|
{Side: types.SideTypeSell, Price: Number("2.0068"), Quantity: Number("192.20")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0082"), Quantity: Number("2016.13")},
|
{Side: types.SideTypeSell, Price: Number("2.0082"), Quantity: Number("201.61")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0096"), Quantity: Number("2114.85")},
|
{Side: types.SideTypeSell, Price: Number("2.0096"), Quantity: Number("211.48")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0110"), Quantity: Number("2218.40")},
|
{Side: types.SideTypeSell, Price: Number("2.0110"), Quantity: Number("221.84")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0124"), Quantity: Number("2327.02")},
|
{Side: types.SideTypeSell, Price: Number("2.0124"), Quantity: Number("232.70")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0137"), Quantity: Number("2440.96")},
|
{Side: types.SideTypeSell, Price: Number("2.0137"), Quantity: Number("244.09")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0151"), Quantity: Number("2560.48")},
|
{Side: types.SideTypeSell, Price: Number("2.0151"), Quantity: Number("256.04")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0165"), Quantity: Number("2685.86")},
|
{Side: types.SideTypeSell, Price: Number("2.0165"), Quantity: Number("268.58")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0179"), Quantity: Number("2817.37")},
|
{Side: types.SideTypeSell, Price: Number("2.0179"), Quantity: Number("281.73")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0193"), Quantity: Number("2955.32")},
|
{Side: types.SideTypeSell, Price: Number("2.0193"), Quantity: Number("295.53")},
|
||||||
}, orders[0:15])
|
}, orders[0:15])
|
||||||
|
|
||||||
AssertOrdersPriceSideQuantity(t, []PriceSideQuantityAssert{
|
AssertOrdersPriceSideQuantity(t, []PriceSideQuantityAssert{
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0386"), Quantity: Number("5771.04")},
|
{Side: types.SideTypeSell, Price: Number("2.0386"), Quantity: Number("577.10")},
|
||||||
{Side: types.SideTypeSell, Price: Number("2.0399"), Quantity: Number("6053.62")},
|
{Side: types.SideTypeSell, Price: Number("2.0399"), Quantity: Number("605.36")},
|
||||||
}, orders[28:30])
|
}, orders[28:30])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -89,26 +89,26 @@ func TestLiquidityOrderGenerator(t *testing.T) {
|
||||||
assert.InDelta(t, totalAmount.Float64(), totalQuoteQuantity.Float64(), 1.0)
|
assert.InDelta(t, totalAmount.Float64(), totalQuoteQuantity.Float64(), 1.0)
|
||||||
|
|
||||||
AssertOrdersPriceSideQuantity(t, []PriceSideQuantityAssert{
|
AssertOrdersPriceSideQuantity(t, []PriceSideQuantityAssert{
|
||||||
{Side: types.SideTypeBuy, Price: Number("2.0000"), Quantity: Number("1551.37")},
|
{Side: types.SideTypeBuy, Price: Number("2.0000"), Quantity: Number("155.13")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9986"), Quantity: Number("1627.33")},
|
{Side: types.SideTypeBuy, Price: Number("1.9986"), Quantity: Number("162.73")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9972"), Quantity: Number("1707.01")},
|
{Side: types.SideTypeBuy, Price: Number("1.9972"), Quantity: Number("170.70")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9958"), Quantity: Number("1790.59")},
|
{Side: types.SideTypeBuy, Price: Number("1.9958"), Quantity: Number("179.05")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9944"), Quantity: Number("1878.27")},
|
{Side: types.SideTypeBuy, Price: Number("1.9944"), Quantity: Number("187.82")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9931"), Quantity: Number("1970.24")},
|
{Side: types.SideTypeBuy, Price: Number("1.9931"), Quantity: Number("197.02")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9917"), Quantity: Number("2066.71")},
|
{Side: types.SideTypeBuy, Price: Number("1.9917"), Quantity: Number("206.67")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9903"), Quantity: Number("2167.91")},
|
{Side: types.SideTypeBuy, Price: Number("1.9903"), Quantity: Number("216.79")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9889"), Quantity: Number("2274.06")},
|
{Side: types.SideTypeBuy, Price: Number("1.9889"), Quantity: Number("227.40")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9875"), Quantity: Number("2385.40")},
|
{Side: types.SideTypeBuy, Price: Number("1.9875"), Quantity: Number("238.54")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9862"), Quantity: Number("2502.20")},
|
{Side: types.SideTypeBuy, Price: Number("1.9862"), Quantity: Number("250.22")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9848"), Quantity: Number("2624.72")},
|
{Side: types.SideTypeBuy, Price: Number("1.9848"), Quantity: Number("262.47")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9834"), Quantity: Number("2753.24")},
|
{Side: types.SideTypeBuy, Price: Number("1.9834"), Quantity: Number("275.32")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9820"), Quantity: Number("2888.05")},
|
{Side: types.SideTypeBuy, Price: Number("1.9820"), Quantity: Number("288.80")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9806"), Quantity: Number("3029.46")},
|
{Side: types.SideTypeBuy, Price: Number("1.9806"), Quantity: Number("302.94")},
|
||||||
}, orders[0:15])
|
}, orders[0:15])
|
||||||
|
|
||||||
AssertOrdersPriceSideQuantity(t, []PriceSideQuantityAssert{
|
AssertOrdersPriceSideQuantity(t, []PriceSideQuantityAssert{
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9613"), Quantity: Number("5915.83")},
|
{Side: types.SideTypeBuy, Price: Number("1.9613"), Quantity: Number("591.58")},
|
||||||
{Side: types.SideTypeBuy, Price: Number("1.9600"), Quantity: Number("6205.49")},
|
{Side: types.SideTypeBuy, Price: Number("1.9600"), Quantity: Number("620.54")},
|
||||||
}, orders[28:30])
|
}, orders[28:30])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package liquiditymaker
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
@ -46,13 +45,11 @@ type Strategy struct {
|
||||||
|
|
||||||
NumOfLiquidityLayers int `json:"numOfLiquidityLayers"`
|
NumOfLiquidityLayers int `json:"numOfLiquidityLayers"`
|
||||||
LiquiditySlideRule *bbgo.SlideRule `json:"liquidityScale"`
|
LiquiditySlideRule *bbgo.SlideRule `json:"liquidityScale"`
|
||||||
LiquidityLayerTickSize fixedpoint.Value `json:"liquidityLayerTickSize"`
|
|
||||||
LiquiditySkew fixedpoint.Value `json:"liquiditySkew"`
|
|
||||||
LiquidityPriceRange fixedpoint.Value `json:"liquidityPriceRange"`
|
LiquidityPriceRange fixedpoint.Value `json:"liquidityPriceRange"`
|
||||||
|
|
||||||
AskLiquidityAmount fixedpoint.Value `json:"askLiquidityAmount"`
|
AskLiquidityAmount fixedpoint.Value `json:"askLiquidityAmount"`
|
||||||
BidLiquidityAmount fixedpoint.Value `json:"bidLiquidityAmount"`
|
BidLiquidityAmount fixedpoint.Value `json:"bidLiquidityAmount"`
|
||||||
|
|
||||||
|
UseLastTradePrice bool `json:"useLastTradePrice"`
|
||||||
Spread fixedpoint.Value `json:"spread"`
|
Spread fixedpoint.Value `json:"spread"`
|
||||||
MaxPrice fixedpoint.Value `json:"maxPrice"`
|
MaxPrice fixedpoint.Value `json:"maxPrice"`
|
||||||
MinPrice fixedpoint.Value `json:"minPrice"`
|
MinPrice fixedpoint.Value `json:"minPrice"`
|
||||||
|
@ -65,6 +62,8 @@ type Strategy struct {
|
||||||
book *types.StreamOrderBook
|
book *types.StreamOrderBook
|
||||||
|
|
||||||
liquidityScale bbgo.Scale
|
liquidityScale bbgo.Scale
|
||||||
|
|
||||||
|
orderGenerator *LiquidityOrderGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) ID() string {
|
func (s *Strategy) ID() string {
|
||||||
|
@ -85,6 +84,11 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.
|
||||||
s.Strategy = &common.Strategy{}
|
s.Strategy = &common.Strategy{}
|
||||||
s.Strategy.Initialize(ctx, s.Environment, session, s.Market, ID, s.InstanceID())
|
s.Strategy.Initialize(ctx, s.Environment, session, s.Market, ID, s.InstanceID())
|
||||||
|
|
||||||
|
s.orderGenerator = &LiquidityOrderGenerator{
|
||||||
|
Symbol: s.Symbol,
|
||||||
|
Market: s.Market,
|
||||||
|
}
|
||||||
|
|
||||||
s.book = types.NewStreamBook(s.Symbol)
|
s.book = types.NewStreamBook(s.Symbol)
|
||||||
s.book.BindStream(session.MarketDataStream)
|
s.book.BindStream(session.MarketDataStream)
|
||||||
|
|
||||||
|
@ -209,6 +213,11 @@ func (s *Strategy) placeAdjustmentOrders(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) placeLiquidityOrders(ctx context.Context) {
|
func (s *Strategy) placeLiquidityOrders(ctx context.Context) {
|
||||||
|
err := s.liquidityOrderBook.GracefulCancel(ctx, s.Session.Exchange)
|
||||||
|
if logErr(err, "unable to cancel orders") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ticker, err := s.Session.Exchange.QueryTicker(ctx, s.Symbol)
|
ticker, err := s.Session.Exchange.QueryTicker(ctx, s.Symbol)
|
||||||
if logErr(err, "unable to query ticker") {
|
if logErr(err, "unable to query ticker") {
|
||||||
return
|
return
|
||||||
|
@ -219,11 +228,14 @@ func (s *Strategy) placeLiquidityOrders(ctx context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.liquidityOrderBook.GracefulCancel(ctx, s.Session.Exchange)
|
if _, err := s.Session.UpdateAccount(ctx); err != nil {
|
||||||
if logErr(err, "unable to cancel orders") {
|
logErr(err, "unable to update account")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseBal, _ := s.Session.Account.Balance(s.Market.BaseCurrency)
|
||||||
|
quoteBal, _ := s.Session.Account.Balance(s.Market.QuoteCurrency)
|
||||||
|
|
||||||
if ticker.Buy.IsZero() && ticker.Sell.IsZero() {
|
if ticker.Buy.IsZero() && ticker.Sell.IsZero() {
|
||||||
ticker.Sell = ticker.Last.Add(s.Market.TickSize)
|
ticker.Sell = ticker.Last.Add(s.Market.TickSize)
|
||||||
ticker.Buy = ticker.Last.Sub(s.Market.TickSize)
|
ticker.Buy = ticker.Last.Sub(s.Market.TickSize)
|
||||||
|
@ -233,78 +245,32 @@ func (s *Strategy) placeLiquidityOrders(ctx context.Context) {
|
||||||
ticker.Sell = ticker.Buy.Add(s.Market.TickSize)
|
ticker.Sell = ticker.Buy.Add(s.Market.TickSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := s.Session.UpdateAccount(ctx); err != nil {
|
log.Infof("ticker: %+v", ticker)
|
||||||
logErr(err, "unable to update account")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
baseBal, _ := s.Session.Account.Balance(s.Market.BaseCurrency)
|
|
||||||
quoteBal, _ := s.Session.Account.Balance(s.Market.QuoteCurrency)
|
|
||||||
|
|
||||||
lastTradedPrice := ticker.Last
|
lastTradedPrice := ticker.Last
|
||||||
midPrice := ticker.Sell.Add(ticker.Buy).Div(fixedpoint.Two)
|
midPrice := ticker.Sell.Add(ticker.Buy).Div(fixedpoint.Two)
|
||||||
currentSpread := ticker.Sell.Sub(ticker.Buy)
|
currentSpread := ticker.Sell.Sub(ticker.Buy)
|
||||||
tickSize := fixedpoint.Max(s.LiquidityLayerTickSize, s.Market.TickSize)
|
|
||||||
sideSpread := s.Spread.Div(fixedpoint.Two)
|
sideSpread := s.Spread.Div(fixedpoint.Two)
|
||||||
|
|
||||||
log.Infof("current: spread: %f lastTradedPrice: %f midPrice: %f", currentSpread.Float64(), lastTradedPrice.Float64(), midPrice.Float64())
|
if s.UseLastTradePrice {
|
||||||
|
midPrice = lastTradedPrice
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("current spread: %f lastTradedPrice: %f midPrice: %f", currentSpread.Float64(), lastTradedPrice.Float64(), midPrice.Float64())
|
||||||
|
|
||||||
ask1Price := midPrice.Mul(fixedpoint.One.Add(sideSpread))
|
ask1Price := midPrice.Mul(fixedpoint.One.Add(sideSpread))
|
||||||
bid1Price := midPrice.Mul(fixedpoint.One.Sub(sideSpread))
|
bid1Price := midPrice.Mul(fixedpoint.One.Sub(sideSpread))
|
||||||
|
|
||||||
askLastPrice := midPrice.Mul(fixedpoint.One.Add(s.LiquidityPriceRange))
|
askLastPrice := midPrice.Mul(fixedpoint.One.Add(s.LiquidityPriceRange))
|
||||||
bidLastPrice := midPrice.Mul(fixedpoint.One.Sub(s.LiquidityPriceRange))
|
bidLastPrice := midPrice.Mul(fixedpoint.One.Sub(s.LiquidityPriceRange))
|
||||||
log.Infof("wanted side spread: %f askRange: %f ~ %f bidRange: %f ~ %f", sideSpread.Float64(),
|
log.Infof("wanted side spread: %f askRange: %f ~ %f bidRange: %f ~ %f",
|
||||||
|
sideSpread.Float64(),
|
||||||
ask1Price.Float64(), askLastPrice.Float64(),
|
ask1Price.Float64(), askLastPrice.Float64(),
|
||||||
bid1Price.Float64(), bidLastPrice.Float64())
|
bid1Price.Float64(), bidLastPrice.Float64())
|
||||||
|
|
||||||
askLayerSpread := askLastPrice.Sub(ask1Price).Div(fixedpoint.NewFromInt(int64(s.NumOfLiquidityLayers)))
|
|
||||||
bidLayerSpread := bid1Price.Sub(bidLastPrice).Div(fixedpoint.NewFromInt(int64(s.NumOfLiquidityLayers)))
|
|
||||||
|
|
||||||
if askLayerSpread.Compare(tickSize) < 0 {
|
|
||||||
askLayerSpread = tickSize
|
|
||||||
}
|
|
||||||
|
|
||||||
if bidLayerSpread.Compare(tickSize) < 0 {
|
|
||||||
bidLayerSpread = tickSize
|
|
||||||
}
|
|
||||||
|
|
||||||
sum := s.liquidityScale.Sum(1.0)
|
|
||||||
askSum := sum
|
|
||||||
bidSum := sum
|
|
||||||
log.Infof("liquidity sum: %f / %f", askSum, bidSum)
|
|
||||||
|
|
||||||
skew := s.LiquiditySkew.Float64()
|
|
||||||
useSkew := !s.LiquiditySkew.IsZero()
|
|
||||||
if useSkew {
|
|
||||||
askSum = sum / skew
|
|
||||||
bidSum = sum * skew
|
|
||||||
log.Infof("adjusted liqudity skew: %f / %f", askSum, bidSum)
|
|
||||||
}
|
|
||||||
|
|
||||||
var bidPrices []fixedpoint.Value
|
|
||||||
var askPrices []fixedpoint.Value
|
|
||||||
|
|
||||||
// calculate and collect prices
|
|
||||||
for i := 0; i <= s.NumOfLiquidityLayers; i++ {
|
|
||||||
fi := fixedpoint.NewFromInt(int64(i))
|
|
||||||
bidPrice := bid1Price.Sub(bidLayerSpread.Mul(fi))
|
|
||||||
askPrice := ask1Price.Add(askLayerSpread.Mul(fi))
|
|
||||||
|
|
||||||
bidPrice = s.Market.TruncatePrice(bidPrice)
|
|
||||||
askPrice = s.Market.TruncatePrice(askPrice)
|
|
||||||
|
|
||||||
bidPrices = append(bidPrices, bidPrice)
|
|
||||||
askPrices = append(askPrices, askPrice)
|
|
||||||
}
|
|
||||||
|
|
||||||
availableBase := baseBal.Available
|
availableBase := baseBal.Available
|
||||||
availableQuote := quoteBal.Available
|
availableQuote := quoteBal.Available
|
||||||
|
|
||||||
makerQuota := &bbgo.QuotaTransaction{}
|
|
||||||
makerQuota.QuoteAsset.Add(availableQuote)
|
|
||||||
makerQuota.BaseAsset.Add(availableBase)
|
|
||||||
|
|
||||||
log.Infof("balances before liq orders: %s, %s",
|
log.Infof("balances before liq orders: %s, %s",
|
||||||
baseBal.String(),
|
baseBal.String(),
|
||||||
quoteBal.String())
|
quoteBal.String())
|
||||||
|
@ -319,79 +285,32 @@ func (s *Strategy) placeLiquidityOrders(ctx context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
askX := availableBase.Float64() / askSum
|
bidOrders := s.orderGenerator.Generate(types.SideTypeBuy,
|
||||||
bidX := availableQuote.Float64() / (bidSum * (fixedpoint.Sum(bidPrices).Float64()))
|
fixedpoint.Min(s.BidLiquidityAmount, quoteBal.Available),
|
||||||
|
bid1Price,
|
||||||
|
bidLastPrice,
|
||||||
|
s.NumOfLiquidityLayers,
|
||||||
|
s.liquidityScale)
|
||||||
|
|
||||||
askX = math.Trunc(askX*1e8) / 1e8
|
askOrders := s.orderGenerator.Generate(types.SideTypeSell,
|
||||||
bidX = math.Trunc(bidX*1e8) / 1e8
|
s.AskLiquidityAmount,
|
||||||
|
ask1Price,
|
||||||
|
askLastPrice,
|
||||||
|
s.NumOfLiquidityLayers,
|
||||||
|
s.liquidityScale)
|
||||||
|
|
||||||
var liqOrders []types.SubmitOrder
|
orderForms := append(bidOrders, askOrders...)
|
||||||
for i := 0; i <= s.NumOfLiquidityLayers; i++ {
|
|
||||||
bidQuantity := fixedpoint.NewFromFloat(s.liquidityScale.Call(float64(i)) * bidX)
|
|
||||||
askQuantity := fixedpoint.NewFromFloat(s.liquidityScale.Call(float64(i)) * askX)
|
|
||||||
bidPrice := bidPrices[i]
|
|
||||||
askPrice := askPrices[i]
|
|
||||||
|
|
||||||
log.Infof("liqudity layer #%d %f/%f = %f/%f", i, askPrice.Float64(), bidPrice.Float64(), askQuantity.Float64(), bidQuantity.Float64())
|
createdOrders, err := s.OrderExecutor.SubmitOrders(ctx, orderForms...)
|
||||||
|
|
||||||
placeBuy := true
|
|
||||||
placeSell := true
|
|
||||||
averageCost := s.Position.AverageCost
|
|
||||||
// when long position, do not place sell orders below the average cost
|
|
||||||
if !s.Position.IsDust() {
|
|
||||||
if s.Position.IsLong() && askPrice.Compare(averageCost) < 0 {
|
|
||||||
placeSell = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Position.IsShort() && bidPrice.Compare(averageCost) > 0 {
|
|
||||||
placeBuy = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
quoteQuantity := bidQuantity.Mul(bidPrice)
|
|
||||||
|
|
||||||
if s.Market.IsDustQuantity(bidQuantity, bidPrice) || !makerQuota.QuoteAsset.Lock(quoteQuantity) {
|
|
||||||
placeBuy = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Market.IsDustQuantity(askQuantity, askPrice) || !makerQuota.BaseAsset.Lock(askQuantity) {
|
|
||||||
placeSell = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if placeBuy {
|
|
||||||
liqOrders = append(liqOrders, types.SubmitOrder{
|
|
||||||
Symbol: s.Symbol,
|
|
||||||
Side: types.SideTypeBuy,
|
|
||||||
Type: types.OrderTypeLimitMaker,
|
|
||||||
Quantity: bidQuantity,
|
|
||||||
Price: bidPrice,
|
|
||||||
Market: s.Market,
|
|
||||||
TimeInForce: types.TimeInForceGTC,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if placeSell {
|
|
||||||
liqOrders = append(liqOrders, types.SubmitOrder{
|
|
||||||
Symbol: s.Symbol,
|
|
||||||
Side: types.SideTypeSell,
|
|
||||||
Type: types.OrderTypeLimitMaker,
|
|
||||||
Quantity: askQuantity,
|
|
||||||
Price: askPrice,
|
|
||||||
Market: s.Market,
|
|
||||||
TimeInForce: types.TimeInForceGTC,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
makerQuota.Commit()
|
|
||||||
|
|
||||||
createdOrders, err := s.OrderExecutor.SubmitOrders(ctx, liqOrders...)
|
|
||||||
if logErr(err, "unable to place liquidity orders") {
|
if logErr(err, "unable to place liquidity orders") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.liquidityOrderBook.Add(createdOrders...)
|
s.liquidityOrderBook.Add(createdOrders...)
|
||||||
log.Infof("%d liq orders are placed successfully", len(liqOrders))
|
log.Infof("%d liq orders are placed successfully", len(orderForms))
|
||||||
|
for _, o := range createdOrders {
|
||||||
|
log.Infof("liq order: %+v", o)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func profitProtectedPrice(
|
func profitProtectedPrice(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user