diff --git a/bbgo/calc.go b/bbgo/calc.go index 002ea0e02..7f6df2235 100644 --- a/bbgo/calc.go +++ b/bbgo/calc.go @@ -22,14 +22,27 @@ func SellVolumeModifier(price float64) float64 { return math.Min(2, math.Exp((price-targetPrice)/flatness)) } -func VolumeByPriceChange(currentPrice float64, change float64, side binance.SideType) float64 { +func VolumeByPriceChange(market Market, currentPrice float64, change float64, side binance.SideType) float64 { volume := BaseVolumeByPriceChange(change) if side == binance.SideTypeSell { - return volume * SellVolumeModifier(currentPrice) + volume *= SellVolumeModifier(currentPrice) + } else { + volume *= volume*BuyVolumeModifier(currentPrice) } - return math.Max(MinQuantity, volume*BuyVolumeModifier(currentPrice)) + // at least the minimal quantity + volume = math.Max(market.MinQuantity, volume) + + // modify volume for the min amount + amount := currentPrice * volume + if amount < market.MinAmount { + ratio := market.MinAmount / amount + volume *= ratio + } + + volume = math.Trunc(volume * math.Pow10(market.VolumePrecision)) / math.Pow10(market.VolumePrecision) + return volume } func BaseVolumeByPriceChange(change float64) float64 { diff --git a/bbgo/calc_test.go b/bbgo/calc_test.go new file mode 100644 index 000000000..3aee52b3e --- /dev/null +++ b/bbgo/calc_test.go @@ -0,0 +1,78 @@ +package bbgo + +import ( + "github.com/adshao/go-binance" + "testing" +) + +func TestVolumeByPriceChange(t *testing.T) { + type args struct { + market Market + currentPrice float64 + change float64 + side binance.SideType + } + tests := []struct { + name string + args args + want float64 + }{ + { + name: "buy-change-50-at-9400", + args: args{ + market: MarketBTCUSDT, + currentPrice: 9400, + change: 50, + side: binance.SideTypeBuy, + }, + want: 0.00106382, + }, + { + name: "buy-change-100-at-9200", + args: args{ + market: MarketBTCUSDT, + currentPrice: 9200, + change: 100, + side: binance.SideTypeBuy, + }, + want: 0.00108695, + }, + { + name: "sell-change-100-at-9500", + args: args{ + market: MarketBTCUSDT, + currentPrice: 9500, + change: 100, + side: binance.SideTypeSell, + }, + want: 0.00249052, + }, + { + name: "sell-change-200-at-9600", + args: args{ + market: MarketBTCUSDT, + currentPrice: 9500, + change: 200, + side: binance.SideTypeSell, + }, + want: 0.00265114, + }, + { + name: "sell-change-500-at-9600", + args: args{ + market: MarketBTCUSDT, + currentPrice: 9600, + change: 500, + side: binance.SideTypeSell, + }, + want: 0.00390591, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := VolumeByPriceChange(tt.args.market, tt.args.currentPrice, tt.args.change, tt.args.side); got != tt.want { + t.Errorf("VolumeByPriceChange() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/bbgo/kline_detector.go b/bbgo/kline_detector.go index 64d16446c..c678b7bbc 100644 --- a/bbgo/kline_detector.go +++ b/bbgo/kline_detector.go @@ -65,7 +65,7 @@ func (d *KLineDetector) NewOrder(e *KLineEvent, tradingCtx *TradingContext) Orde side = binance.SideTypeSell } - var volume = tradingCtx.Market.FormatVolume(VolumeByPriceChange(kline.GetClose(), kline.GetChange(), side)) + var volume = tradingCtx.Market.FormatVolume(VolumeByPriceChange(tradingCtx.Market, kline.GetClose(), kline.GetChange(), side)) return Order{ Symbol: e.KLine.Symbol, Type: binance.OrderTypeMarket, @@ -140,4 +140,3 @@ func (d *KLineDetector) Detect(e *KLineEvent, tradingCtx *TradingContext) (reaso return "", true } - diff --git a/bbgo/market.go b/bbgo/market.go index 8e82c9c56..902e96b9e 100644 --- a/bbgo/market.go +++ b/bbgo/market.go @@ -6,6 +6,8 @@ type Market struct { Symbol string PricePrecision int VolumePrecision int + MinQuantity float64 + MinAmount float64 } func (m Market) FormatPrice(val float64) string { @@ -16,24 +18,29 @@ func (m Market) FormatVolume(val float64) string { return strconv.FormatFloat(val, 'f', m.VolumePrecision, 64) } - // Binance Markets, this should be defined per exchange -var Markets = map[string]Market{ - "BNBUSDT": { - Symbol: "BNBUSDT", - PricePrecision: 4, - VolumePrecision: 2, - }, - "BTCUSDT": { + +var MarketBTCUSDT = Market{ Symbol: "BTCUSDT", PricePrecision: 2, VolumePrecision: 8, - }, + MinQuantity: 0.00000100, + MinAmount: 10.0, +} +var MarketBNBUSDT = Market{ + Symbol: "BNBUSDT", + PricePrecision: 4, + VolumePrecision: 2, + MinQuantity: 0.01, + MinAmount: 10.0, } -func FindMarket(symbol string) (m Market, ok bool) { - m , ok = Markets[symbol] +var Markets = map[string]Market{ + "BNBUSDT": MarketBNBUSDT, + "BTCUSDT": MarketBTCUSDT, +} + +func FindMarket(symbol string) (m Market, ok bool) { + m, ok = Markets[symbol] return m, ok } - -