mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
drop legacy OrderProcessor and remove slack debug
This commit is contained in:
parent
468864302e
commit
b22e0370b3
|
@ -144,7 +144,6 @@ func (e *BasicRiskControlOrderExecutor) SubmitOrders(ctx context.Context, orders
|
||||||
e.Notify(":memo: Submitting %s %s %s order with quantity %s @ %s", o.Symbol, o.Side, o.Type, o.QuantityString, o.PriceString, o)
|
e.Notify(":memo: Submitting %s %s %s order with quantity %s @ %s", o.Symbol, o.Side, o.Type, o.QuantityString, o.PriceString, o)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return e.session.Exchange.SubmitOrders(ctx, formattedOrders...)
|
return e.session.Exchange.SubmitOrders(ctx, formattedOrders...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
package bbgo
|
package bbgo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -17,118 +13,93 @@ var (
|
||||||
ErrAssetBalanceLevelTooHigh = errors.New("asset balance level too high")
|
ErrAssetBalanceLevelTooHigh = errors.New("asset balance level too high")
|
||||||
)
|
)
|
||||||
|
|
||||||
// OrderProcessor does:
|
/*
|
||||||
// - Check quote balance
|
tradingCtx := p.OrderExecutor.Context
|
||||||
// - Check and control the order amount
|
currentPrice := tradingCtx.CurrentPrice
|
||||||
// - Adjust order amount due to the minAmount configuration and maxAmount configuration
|
market := order.Market
|
||||||
// - Canonicalize the volume precision base on the given exchange
|
quantity := order.Quantity
|
||||||
type OrderProcessor struct {
|
|
||||||
// balance control
|
|
||||||
MinQuoteBalance float64 `json:"minQuoteBalance"`
|
|
||||||
MaxAssetBalance float64 `json:"maxBaseAssetBalance"`
|
|
||||||
MinAssetBalance float64 `json:"minBaseAssetBalance"`
|
|
||||||
MaxOrderAmount float64 `json:"maxOrderAmount"`
|
|
||||||
|
|
||||||
// MinProfitSpread is used when submitting sell orders, it check if there the selling can make the profit.
|
tradingCtx.Lock()
|
||||||
MinProfitSpread float64 `json:"minProfitSpread"`
|
defer tradingCtx.Unlock()
|
||||||
|
|
||||||
|
switch order.Side {
|
||||||
|
case types.SideTypeBuy:
|
||||||
|
|
||||||
Exchange types.Exchange `json:"-"`
|
if balance, ok := tradingCtx.Balances[market.QuoteCurrency]; ok {
|
||||||
}
|
if balance.Available < p.MinQuoteBalance {
|
||||||
|
return errors.Wrapf(ErrQuoteBalanceLevelTooLow, "quote balance level is too low: %s < %s",
|
||||||
|
types.USD.FormatMoneyFloat64(balance.Available),
|
||||||
|
types.USD.FormatMoneyFloat64(p.MinQuoteBalance))
|
||||||
|
}
|
||||||
|
|
||||||
func (p *OrderProcessor) Submit(ctx context.Context, order types.SubmitOrder) error {
|
if baseBalance, ok := tradingCtx.Balances[market.BaseCurrency]; ok {
|
||||||
/*
|
if util.NotZero(p.MaxAssetBalance) && baseBalance.Available > p.MaxAssetBalance {
|
||||||
tradingCtx := p.OrderExecutor.Context
|
return errors.Wrapf(ErrAssetBalanceLevelTooHigh, "asset balance level is too high: %f > %f", baseBalance.Available, p.MaxAssetBalance)
|
||||||
currentPrice := tradingCtx.CurrentPrice
|
|
||||||
market := order.Market
|
|
||||||
quantity := order.Quantity
|
|
||||||
|
|
||||||
tradingCtx.Lock()
|
|
||||||
defer tradingCtx.Unlock()
|
|
||||||
|
|
||||||
switch order.Side {
|
|
||||||
case types.SideTypeBuy:
|
|
||||||
|
|
||||||
if balance, ok := tradingCtx.Balances[market.QuoteCurrency]; ok {
|
|
||||||
if balance.Available < p.MinQuoteBalance {
|
|
||||||
return errors.Wrapf(ErrQuoteBalanceLevelTooLow, "quote balance level is too low: %s < %s",
|
|
||||||
types.USD.FormatMoneyFloat64(balance.Available),
|
|
||||||
types.USD.FormatMoneyFloat64(p.MinQuoteBalance))
|
|
||||||
}
|
|
||||||
|
|
||||||
if baseBalance, ok := tradingCtx.Balances[market.BaseCurrency]; ok {
|
|
||||||
if util.NotZero(p.MaxAssetBalance) && baseBalance.Available > p.MaxAssetBalance {
|
|
||||||
return errors.Wrapf(ErrAssetBalanceLevelTooHigh, "asset balance level is too high: %f > %f", baseBalance.Available, p.MaxAssetBalance)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
available := math.Max(0.0, balance.Available-p.MinQuoteBalance)
|
|
||||||
|
|
||||||
if available < market.MinAmount {
|
|
||||||
return errors.Wrapf(ErrInsufficientQuoteBalance, "insufficient quote balance: %f < min amount %f", available, market.MinAmount)
|
|
||||||
}
|
|
||||||
|
|
||||||
quantity = adjustQuantityByMinAmount(quantity, currentPrice, market.MinAmount*1.01)
|
|
||||||
quantity = adjustQuantityByMaxAmount(quantity, currentPrice, available)
|
|
||||||
amount := quantity * currentPrice
|
|
||||||
if amount < market.MinAmount {
|
|
||||||
return fmt.Errorf("amount too small: %f < min amount %f", amount, market.MinAmount)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case types.SideTypeSell:
|
available := math.Max(0.0, balance.Available-p.MinQuoteBalance)
|
||||||
|
|
||||||
if balance, ok := tradingCtx.Balances[market.BaseCurrency]; ok {
|
if available < market.MinAmount {
|
||||||
if util.NotZero(p.MinAssetBalance) && balance.Available < p.MinAssetBalance {
|
return errors.Wrapf(ErrInsufficientQuoteBalance, "insufficient quote balance: %f < min amount %f", available, market.MinAmount)
|
||||||
return errors.Wrapf(ErrAssetBalanceLevelTooLow, "asset balance level is too low: %f > %f", balance.Available, p.MinAssetBalance)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
quantity = adjustQuantityByMinAmount(quantity, currentPrice, market.MinNotional*1.01)
|
quantity = adjustQuantityByMinAmount(quantity, currentPrice, market.MinAmount*1.01)
|
||||||
|
quantity = adjustQuantityByMaxAmount(quantity, currentPrice, available)
|
||||||
available := balance.Available
|
amount := quantity * currentPrice
|
||||||
quantity = math.Min(quantity, available)
|
if amount < market.MinAmount {
|
||||||
if quantity < market.MinQuantity {
|
return fmt.Errorf("amount too small: %f < min amount %f", amount, market.MinAmount)
|
||||||
return errors.Wrapf(ErrInsufficientAssetBalance, "insufficient asset balance: %f > minimal quantity %f", available, market.MinQuantity)
|
|
||||||
}
|
|
||||||
|
|
||||||
notional := quantity * currentPrice
|
|
||||||
if notional < tradingCtx.Market.MinNotional {
|
|
||||||
return fmt.Errorf("notional %f < min notional: %f", notional, market.MinNotional)
|
|
||||||
}
|
|
||||||
|
|
||||||
// price tick10
|
|
||||||
// 2 -> 0.01 -> 0.1
|
|
||||||
// 4 -> 0.0001 -> 0.001
|
|
||||||
tick10 := math.Pow10(-market.PricePrecision + 1)
|
|
||||||
minProfitSpread := math.Max(p.MinProfitSpread, tick10)
|
|
||||||
estimatedFee := currentPrice * 0.0015 * 2 // double the fee
|
|
||||||
targetPrice := currentPrice - estimatedFee - minProfitSpread
|
|
||||||
|
|
||||||
stockQuantity := tradingCtx.StockManager.Stocks.QuantityBelowPrice(targetPrice)
|
|
||||||
if math.Round(stockQuantity*1e8) == 0.0 {
|
|
||||||
return fmt.Errorf("profitable stock not found: target price %f, profit spread: %f", targetPrice, minProfitSpread)
|
|
||||||
}
|
|
||||||
|
|
||||||
quantity = math.Min(quantity, stockQuantity)
|
|
||||||
if quantity < market.MinLot {
|
|
||||||
return fmt.Errorf("quantity %f less than min lot %f", quantity, market.MinLot)
|
|
||||||
}
|
|
||||||
|
|
||||||
notional = quantity * currentPrice
|
|
||||||
if notional < tradingCtx.Market.MinNotional {
|
|
||||||
return fmt.Errorf("notional %f < min notional: %f", notional, market.MinNotional)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
order.Quantity = quantity
|
case types.SideTypeSell:
|
||||||
order.QuantityString = market.FormatVolume(quantity)
|
|
||||||
*/
|
|
||||||
|
|
||||||
createdOrders, err := p.Exchange.SubmitOrders(ctx, order)
|
if balance, ok := tradingCtx.Balances[market.BaseCurrency]; ok {
|
||||||
_ = createdOrders
|
if util.NotZero(p.MinAssetBalance) && balance.Available < p.MinAssetBalance {
|
||||||
return err
|
return errors.Wrapf(ErrAssetBalanceLevelTooLow, "asset balance level is too low: %f > %f", balance.Available, p.MinAssetBalance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quantity = adjustQuantityByMinAmount(quantity, currentPrice, market.MinNotional*1.01)
|
||||||
|
|
||||||
|
available := balance.Available
|
||||||
|
quantity = math.Min(quantity, available)
|
||||||
|
if quantity < market.MinQuantity {
|
||||||
|
return errors.Wrapf(ErrInsufficientAssetBalance, "insufficient asset balance: %f > minimal quantity %f", available, market.MinQuantity)
|
||||||
|
}
|
||||||
|
|
||||||
|
notional := quantity * currentPrice
|
||||||
|
if notional < tradingCtx.Market.MinNotional {
|
||||||
|
return fmt.Errorf("notional %f < min notional: %f", notional, market.MinNotional)
|
||||||
|
}
|
||||||
|
|
||||||
|
// price tick10
|
||||||
|
// 2 -> 0.01 -> 0.1
|
||||||
|
// 4 -> 0.0001 -> 0.001
|
||||||
|
tick10 := math.Pow10(-market.PricePrecision + 1)
|
||||||
|
minProfitSpread := math.Max(p.MinProfitSpread, tick10)
|
||||||
|
estimatedFee := currentPrice * 0.0015 * 2 // double the fee
|
||||||
|
targetPrice := currentPrice - estimatedFee - minProfitSpread
|
||||||
|
|
||||||
|
stockQuantity := tradingCtx.StockManager.Stocks.QuantityBelowPrice(targetPrice)
|
||||||
|
if math.Round(stockQuantity*1e8) == 0.0 {
|
||||||
|
return fmt.Errorf("profitable stock not found: target price %f, profit spread: %f", targetPrice, minProfitSpread)
|
||||||
|
}
|
||||||
|
|
||||||
|
quantity = math.Min(quantity, stockQuantity)
|
||||||
|
if quantity < market.MinLot {
|
||||||
|
return fmt.Errorf("quantity %f less than min lot %f", quantity, market.MinLot)
|
||||||
|
}
|
||||||
|
|
||||||
|
notional = quantity * currentPrice
|
||||||
|
if notional < tradingCtx.Market.MinNotional {
|
||||||
|
return fmt.Errorf("notional %f < min notional: %f", notional, market.MinNotional)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
order.Quantity = quantity
|
||||||
|
order.QuantityString = market.FormatVolume(quantity)
|
||||||
|
*/
|
||||||
|
|
||||||
func adjustQuantityByMinAmount(quantity float64, currentPrice float64, minAmount float64) float64 {
|
func adjustQuantityByMinAmount(quantity float64, currentPrice float64, minAmount float64) float64 {
|
||||||
// modify quantity for the min amount
|
// modify quantity for the min amount
|
||||||
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"github.com/c9s/bbgo/pkg/notifier/slacknotifier"
|
"github.com/c9s/bbgo/pkg/notifier/slacknotifier"
|
||||||
"github.com/c9s/bbgo/pkg/slack/slacklog"
|
"github.com/c9s/bbgo/pkg/slack/slacklog"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var errSlackTokenUndefined = errors.New("slack token is not defined.")
|
var errSlackTokenUndefined = errors.New("slack token is not defined.")
|
||||||
|
@ -117,7 +116,7 @@ func runConfig(ctx context.Context, userConfig *bbgo.Config) error {
|
||||||
log.AddHook(slacklog.NewLogHook(slackToken, conf.ErrorChannel))
|
log.AddHook(slacklog.NewLogHook(slackToken, conf.ErrorChannel))
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("adding slack notifier...")
|
log.Infof("adding slack notifier with default channel: %s", conf.DefaultChannel)
|
||||||
var notifier = slacknotifier.New(slackToken, conf.DefaultChannel)
|
var notifier = slacknotifier.New(slackToken, conf.DefaultChannel)
|
||||||
trader.AddNotifier(notifier)
|
trader.AddNotifier(notifier)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,8 @@ type Notifier struct {
|
||||||
type NotifyOption func(notifier *Notifier)
|
type NotifyOption func(notifier *Notifier)
|
||||||
|
|
||||||
func New(token, channel string, options ...NotifyOption) *Notifier {
|
func New(token, channel string, options ...NotifyOption) *Notifier {
|
||||||
var client = slack.New(token, slack.OptionDebug(true))
|
// var client = slack.New(token, slack.OptionDebug(true))
|
||||||
|
var client = slack.New(token)
|
||||||
|
|
||||||
notifier := &Notifier{
|
notifier := &Notifier{
|
||||||
channel: channel,
|
channel: channel,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user