drop legacy OrderProcessor and remove slack debug

This commit is contained in:
c9s 2020-10-28 17:24:47 +08:00
parent 468864302e
commit b22e0370b3
4 changed files with 77 additions and 107 deletions

View File

@ -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...)
} }

View File

@ -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

View File

@ -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)
} }

View File

@ -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,