mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-13 02:23:51 +00:00
feature: SLTP from bookticker. fix: bookTicker typename, depth buffer error message
This commit is contained in:
parent
668328dd16
commit
71fe6c2d26
|
@ -582,7 +582,7 @@ func (session *ExchangeSession) MarketDataStore(symbol string) (s *MarketDataSto
|
||||||
return s, ok
|
return s, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarketDataStore returns the market data store of a symbol
|
// OrderBook returns the personal orderbook of a symbol
|
||||||
func (session *ExchangeSession) OrderBook(symbol string) (s *types.StreamOrderBook, ok bool) {
|
func (session *ExchangeSession) OrderBook(symbol string) (s *types.StreamOrderBook, ok bool) {
|
||||||
s, ok = session.orderBooks[symbol]
|
s, ok = session.orderBooks[symbol]
|
||||||
return s, ok
|
return s, ok
|
||||||
|
@ -935,9 +935,9 @@ func (session *ExchangeSession) SlackAttachment() slack.Attachment {
|
||||||
return slack.Attachment{
|
return slack.Attachment{
|
||||||
// Pretext: "",
|
// Pretext: "",
|
||||||
// Text: text,
|
// Text: text,
|
||||||
Title: session.Name,
|
Title: session.Name,
|
||||||
Fields: fields,
|
Fields: fields,
|
||||||
FooterIcon: footerIcon,
|
FooterIcon: footerIcon,
|
||||||
Footer: util.Render("update time {{ . }}", time.Now().Format(time.RFC822)),
|
Footer: util.Render("update time {{ . }}", time.Now().Format(time.RFC822)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,13 +117,14 @@ func (b *Buffer) AddUpdate(o types.SliceOrderBook, firstUpdateID int64, finalArg
|
||||||
if u.FirstUpdateID > b.finalUpdateID+1 {
|
if u.FirstUpdateID > b.finalUpdateID+1 {
|
||||||
// emitReset will reset the once outside the mutex lock section
|
// emitReset will reset the once outside the mutex lock section
|
||||||
b.buffer = []Update{u}
|
b.buffer = []Update{u}
|
||||||
|
finalUpdateID = b.finalUpdateID
|
||||||
b.resetSnapshot()
|
b.resetSnapshot()
|
||||||
b.emitReset()
|
b.emitReset()
|
||||||
b.mu.Unlock()
|
b.mu.Unlock()
|
||||||
return fmt.Errorf("found missing update between finalUpdateID %d and firstUpdateID %d, diff: %d",
|
return fmt.Errorf("found missing update between finalUpdateID %d and firstUpdateID %d, diff: %d",
|
||||||
b.finalUpdateID+1,
|
finalUpdateID+1,
|
||||||
u.FirstUpdateID,
|
u.FirstUpdateID,
|
||||||
u.FirstUpdateID-b.finalUpdateID)
|
u.FirstUpdateID-finalUpdateID)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("depth update id %d -> %d", b.finalUpdateID, u.FinalUpdateID)
|
log.Debugf("depth update id %d -> %d", b.finalUpdateID, u.FinalUpdateID)
|
||||||
|
@ -142,6 +143,7 @@ func (b *Buffer) fetchAndPush() error {
|
||||||
log.Debugf("fetched depth snapshot, final update id %d", finalUpdateID)
|
log.Debugf("fetched depth snapshot, final update id %d", finalUpdateID)
|
||||||
|
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
|
|
||||||
if len(b.buffer) > 0 {
|
if len(b.buffer) > 0 {
|
||||||
// the snapshot is too early
|
// the snapshot is too early
|
||||||
if finalUpdateID < b.buffer[0].FirstUpdateID {
|
if finalUpdateID < b.buffer[0].FirstUpdateID {
|
||||||
|
|
|
@ -1428,9 +1428,22 @@ func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *type
|
||||||
|
|
||||||
// QueryDepth query the order book depth of a symbol
|
// QueryDepth query the order book depth of a symbol
|
||||||
func (e *Exchange) QueryDepth(ctx context.Context, symbol string) (snapshot types.SliceOrderBook, finalUpdateID int64, err error) {
|
func (e *Exchange) QueryDepth(ctx context.Context, symbol string) (snapshot types.SliceOrderBook, finalUpdateID int64, err error) {
|
||||||
response, err := e.client.NewDepthService().Symbol(symbol).Do(ctx)
|
var response *binance.DepthResponse
|
||||||
if err != nil {
|
if e.IsFutures {
|
||||||
return snapshot, finalUpdateID, err
|
res, err := e.futuresClient.NewDepthService().Symbol(symbol).Do(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return snapshot, finalUpdateID, err
|
||||||
|
}
|
||||||
|
response = &binance.DepthResponse{
|
||||||
|
LastUpdateID: res.LastUpdateID,
|
||||||
|
Bids: res.Bids,
|
||||||
|
Asks: res.Asks,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
response, err = e.client.NewDepthService().Symbol(symbol).Do(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return snapshot, finalUpdateID, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot.Symbol = symbol
|
snapshot.Symbol = symbol
|
||||||
|
|
|
@ -113,17 +113,17 @@ func (e *ExecutionReportEvent) Order() (*types.Order, error) {
|
||||||
orderCreationTime := time.Unix(0, e.OrderCreationTime*int64(time.Millisecond))
|
orderCreationTime := time.Unix(0, e.OrderCreationTime*int64(time.Millisecond))
|
||||||
return &types.Order{
|
return &types.Order{
|
||||||
SubmitOrder: types.SubmitOrder{
|
SubmitOrder: types.SubmitOrder{
|
||||||
ClientOrderID: e.ClientOrderID,
|
ClientOrderID: e.ClientOrderID,
|
||||||
Symbol: e.Symbol,
|
Symbol: e.Symbol,
|
||||||
Side: toGlobalSideType(binance.SideType(e.Side)),
|
Side: toGlobalSideType(binance.SideType(e.Side)),
|
||||||
Type: toGlobalOrderType(binance.OrderType(e.OrderType)),
|
Type: toGlobalOrderType(binance.OrderType(e.OrderType)),
|
||||||
Quantity: e.OrderQuantity,
|
Quantity: e.OrderQuantity,
|
||||||
Price: e.OrderPrice,
|
Price: e.OrderPrice,
|
||||||
StopPrice: e.StopPrice,
|
StopPrice: e.StopPrice,
|
||||||
TimeInForce: types.TimeInForce(e.TimeInForce),
|
TimeInForce: types.TimeInForce(e.TimeInForce),
|
||||||
IsFutures: false,
|
IsFutures: false,
|
||||||
ReduceOnly: false,
|
ReduceOnly: false,
|
||||||
ClosePosition: false,
|
ClosePosition: false,
|
||||||
},
|
},
|
||||||
Exchange: types.ExchangeBinance,
|
Exchange: types.ExchangeBinance,
|
||||||
IsWorking: e.IsOnBook,
|
IsWorking: e.IsOnBook,
|
||||||
|
@ -276,7 +276,7 @@ func parseWebSocketEvent(message []byte) (interface{}, error) {
|
||||||
// fmt.Println(str)
|
// fmt.Println(str)
|
||||||
eventType := string(val.GetStringBytes("e"))
|
eventType := string(val.GetStringBytes("e"))
|
||||||
if eventType == "" && IsBookTicker(val) {
|
if eventType == "" && IsBookTicker(val) {
|
||||||
eventType = "bookticker"
|
eventType = "bookTicker"
|
||||||
}
|
}
|
||||||
|
|
||||||
switch eventType {
|
switch eventType {
|
||||||
|
@ -284,7 +284,7 @@ func parseWebSocketEvent(message []byte) (interface{}, error) {
|
||||||
var event KLineEvent
|
var event KLineEvent
|
||||||
err := json.Unmarshal([]byte(message), &event)
|
err := json.Unmarshal([]byte(message), &event)
|
||||||
return &event, err
|
return &event, err
|
||||||
case "bookticker":
|
case "bookTicker":
|
||||||
var event BookTickerEvent
|
var event BookTickerEvent
|
||||||
err := json.Unmarshal([]byte(message), &event)
|
err := json.Unmarshal([]byte(message), &event)
|
||||||
event.Event = eventType
|
event.Event = eventType
|
||||||
|
|
|
@ -23,6 +23,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Strategy struct {
|
type Strategy struct {
|
||||||
|
*bbgo.Environment
|
||||||
Market types.Market
|
Market types.Market
|
||||||
Session *bbgo.ExchangeSession
|
Session *bbgo.ExchangeSession
|
||||||
UseHeikinAshi bool `json:"useHeikinAshi"` // use heikinashi kline
|
UseHeikinAshi bool `json:"useHeikinAshi"` // use heikinashi kline
|
||||||
|
@ -45,6 +46,8 @@ type Strategy struct {
|
||||||
heikinAshi *HeikinAshi
|
heikinAshi *HeikinAshi
|
||||||
peakPrice fixedpoint.Value
|
peakPrice fixedpoint.Value
|
||||||
bottomPrice fixedpoint.Value
|
bottomPrice fixedpoint.Value
|
||||||
|
midPrice fixedpoint.Value
|
||||||
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) ID() string {
|
func (s *Strategy) ID() string {
|
||||||
|
@ -59,6 +62,10 @@ func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) {
|
||||||
log.Infof("subscribe %s", s.Symbol)
|
log.Infof("subscribe %s", s.Symbol)
|
||||||
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: types.Interval1m.String()})
|
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: types.Interval1m.String()})
|
||||||
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.Interval.String()})
|
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.Interval.String()})
|
||||||
|
|
||||||
|
if s.Environment != nil && s.Environment.IsBackTesting() {
|
||||||
|
session.Subscribe(types.BookTickerChannel, s.Symbol, types.SubscribeOptions{})
|
||||||
|
}
|
||||||
s.SmartStops.Subscribe(session)
|
s.SmartStops.Subscribe(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,15 +538,176 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
|
|
||||||
s.SetupIndicators()
|
s.SetupIndicators()
|
||||||
|
|
||||||
|
sellOrderTPSL := func(price fixedpoint.Value) {
|
||||||
|
balances := session.GetAccount().Balances()
|
||||||
|
quoteBalance := balances[s.Market.QuoteCurrency].Available
|
||||||
|
atrx2 := fixedpoint.NewFromFloat(s.atr.Last() * 2)
|
||||||
|
lastPrice := price
|
||||||
|
var ok bool
|
||||||
|
if s.Environment.IsBackTesting() {
|
||||||
|
lastPrice, ok = session.LastPrice(s.Symbol)
|
||||||
|
if !ok {
|
||||||
|
log.Errorf("cannot get last price")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buyall := false
|
||||||
|
if !sellPrice.IsZero() {
|
||||||
|
if s.bottomPrice.IsZero() || s.bottomPrice.Compare(price) > 0 {
|
||||||
|
s.bottomPrice = price
|
||||||
|
}
|
||||||
|
}
|
||||||
|
takeProfit := false
|
||||||
|
bottomBack := s.bottomPrice
|
||||||
|
if !quoteBalance.IsZero() && !sellPrice.IsZero() && !s.DisableShortStop {
|
||||||
|
// TP
|
||||||
|
if !atrx2.IsZero() && s.bottomPrice.Add(atrx2).Compare(lastPrice) >= 0 &&
|
||||||
|
lastPrice.Compare(sellPrice) < 0 {
|
||||||
|
buyall = true
|
||||||
|
s.bottomPrice = fixedpoint.Zero
|
||||||
|
takeProfit = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SL
|
||||||
|
if (!atrx2.IsZero() && sellPrice.Add(atrx2).Compare(lastPrice) <= 0) ||
|
||||||
|
lastPrice.Sub(sellPrice).Div(sellPrice).Compare(s.Stoploss) > 0 {
|
||||||
|
buyall = true
|
||||||
|
s.bottomPrice = fixedpoint.Zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if buyall {
|
||||||
|
totalQuantity := quoteBalance.Div(lastPrice)
|
||||||
|
order := types.SubmitOrder{
|
||||||
|
Symbol: s.Symbol,
|
||||||
|
Side: types.SideTypeBuy,
|
||||||
|
Type: types.OrderTypeMarket,
|
||||||
|
Quantity: totalQuantity,
|
||||||
|
Market: s.Market,
|
||||||
|
}
|
||||||
|
if s.validateOrder(&order) {
|
||||||
|
if takeProfit {
|
||||||
|
log.Errorf("takeprofit buy at %v, avg %v, l: %v, atrx2: %v", lastPrice, sellPrice, bottomBack, atrx2)
|
||||||
|
} else {
|
||||||
|
log.Errorf("stoploss buy at %v, avg %v, l: %v, atrx2: %v", lastPrice, sellPrice, bottomBack, atrx2)
|
||||||
|
}
|
||||||
|
|
||||||
|
createdOrders, err := orderExecutor.SubmitOrders(ctx, order)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Errorf("cannot place order")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Infof("stoploss bought order %v", createdOrders)
|
||||||
|
s.tradeCollector.Process()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buyOrderTPSL := func(price fixedpoint.Value) {
|
||||||
|
balances := session.GetAccount().Balances()
|
||||||
|
baseBalance := balances[s.Market.BaseCurrency].Available
|
||||||
|
atrx2 := fixedpoint.NewFromFloat(s.atr.Last() * 2)
|
||||||
|
lastPrice := price
|
||||||
|
var ok bool
|
||||||
|
if s.Environment.IsBackTesting() {
|
||||||
|
lastPrice, ok = session.LastPrice(s.Symbol)
|
||||||
|
if !ok {
|
||||||
|
log.Errorf("cannot get last price")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sellall := false
|
||||||
|
if !buyPrice.IsZero() {
|
||||||
|
if s.peakPrice.IsZero() || s.peakPrice.Compare(price) < 0 {
|
||||||
|
s.peakPrice = price
|
||||||
|
}
|
||||||
|
}
|
||||||
|
takeProfit := false
|
||||||
|
peakBack := s.peakPrice
|
||||||
|
if !baseBalance.IsZero() && !buyPrice.IsZero() {
|
||||||
|
|
||||||
|
// TP
|
||||||
|
if !atrx2.IsZero() && s.peakPrice.Sub(atrx2).Compare(lastPrice) >= 0 &&
|
||||||
|
lastPrice.Compare(buyPrice) > 0 {
|
||||||
|
sellall = true
|
||||||
|
s.peakPrice = fixedpoint.Zero
|
||||||
|
takeProfit = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SL
|
||||||
|
if buyPrice.Sub(lastPrice).Div(buyPrice).Compare(s.Stoploss) > 0 ||
|
||||||
|
(!atrx2.IsZero() && buyPrice.Sub(atrx2).Compare(lastPrice) >= 0) {
|
||||||
|
sellall = true
|
||||||
|
s.peakPrice = fixedpoint.Zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sellall {
|
||||||
|
order := types.SubmitOrder{
|
||||||
|
Symbol: s.Symbol,
|
||||||
|
Side: types.SideTypeSell,
|
||||||
|
Type: types.OrderTypeMarket,
|
||||||
|
Market: s.Market,
|
||||||
|
Quantity: baseBalance,
|
||||||
|
}
|
||||||
|
if s.validateOrder(&order) {
|
||||||
|
if takeProfit {
|
||||||
|
log.Errorf("takeprofit sell at %v, avg %v, h: %v, atrx2: %v", lastPrice, buyPrice, peakBack, atrx2)
|
||||||
|
} else {
|
||||||
|
log.Errorf("stoploss sell at %v, avg %v, h: %v, atrx2: %v", lastPrice, buyPrice, peakBack, atrx2)
|
||||||
|
}
|
||||||
|
createdOrders, err := orderExecutor.SubmitOrders(ctx, order)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Errorf("cannot place order")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Infof("stoploss sold order %v", createdOrders)
|
||||||
|
s.tradeCollector.Process()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set last price by realtime book ticker update
|
||||||
|
// to trigger TP/SL
|
||||||
|
session.MarketDataStream.OnBookTickerUpdate(func(ticker types.BookTicker) {
|
||||||
|
if s.Environment.IsBackTesting() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bestBid := ticker.Buy
|
||||||
|
bestAsk := ticker.Sell
|
||||||
|
var midPrice fixedpoint.Value
|
||||||
|
if s.lock.TryLock() {
|
||||||
|
if !bestAsk.IsZero() && !bestBid.IsZero() {
|
||||||
|
s.midPrice = bestAsk.Add(bestBid).Div(types.Two)
|
||||||
|
} else if !bestAsk.IsZero() {
|
||||||
|
s.midPrice = bestAsk
|
||||||
|
} else {
|
||||||
|
s.midPrice = bestBid
|
||||||
|
}
|
||||||
|
midPrice = s.midPrice
|
||||||
|
s.lock.Unlock()
|
||||||
|
}
|
||||||
|
if !midPrice.IsZero() {
|
||||||
|
buyOrderTPSL(midPrice)
|
||||||
|
sellOrderTPSL(midPrice)
|
||||||
|
}
|
||||||
|
//log.Infof("best bid %v, best ask %v, mid %v", bestBid, bestAsk, midPrice)
|
||||||
|
})
|
||||||
|
|
||||||
session.MarketDataStream.OnKLineClosed(func(kline types.KLine) {
|
session.MarketDataStream.OnKLineClosed(func(kline types.KLine) {
|
||||||
if kline.Symbol != s.Symbol {
|
if kline.Symbol != s.Symbol {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var lastPrice fixedpoint.Value
|
||||||
lastPrice, ok := session.LastPrice(s.Symbol)
|
var ok bool
|
||||||
if !ok {
|
if s.Environment.IsBackTesting() {
|
||||||
log.Errorf("cannot get last price")
|
lastPrice, ok = session.LastPrice(s.Symbol)
|
||||||
return
|
if !ok {
|
||||||
|
log.Errorf("cannot get last price")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.lock.RLock()
|
||||||
|
lastPrice = s.midPrice
|
||||||
|
s.lock.RUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// cancel non-traded orders
|
// cancel non-traded orders
|
||||||
|
@ -558,12 +726,10 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
s.tradeCollector.Process()
|
s.tradeCollector.Process()
|
||||||
}
|
}
|
||||||
|
|
||||||
balances := session.GetAccount().Balances()
|
|
||||||
baseBalance := balances[s.Market.BaseCurrency].Available
|
|
||||||
quoteBalance := balances[s.Market.QuoteCurrency].Available
|
|
||||||
atrx2 := fixedpoint.NewFromFloat(s.atr.Last() * 2)
|
atrx2 := fixedpoint.NewFromFloat(s.atr.Last() * 2)
|
||||||
log.Infof("Get last price: %v, kline: %v, balance[base]: %v balance[quote]: %v, atrx2: %v",
|
if !s.Environment.IsBackTesting() {
|
||||||
lastPrice, kline, baseBalance, quoteBalance, atrx2)
|
log.Infof("Get last price: %v, kline: %v, atrx2: %v", lastPrice, kline, atrx2)
|
||||||
|
}
|
||||||
|
|
||||||
// well, only track prices on 1m
|
// well, only track prices on 1m
|
||||||
if kline.Interval == types.Interval1m {
|
if kline.Interval == types.Interval1m {
|
||||||
|
@ -590,105 +756,11 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
log.Infof("repost order %v", createdOrders)
|
log.Infof("repost order %v", createdOrders)
|
||||||
s.tradeCollector.Process()
|
s.tradeCollector.Process()
|
||||||
}
|
}
|
||||||
sellall := false
|
|
||||||
buyall := false
|
|
||||||
if !buyPrice.IsZero() {
|
|
||||||
if s.peakPrice.IsZero() || s.peakPrice.Compare(kline.High) < 0 {
|
|
||||||
s.peakPrice = kline.High
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !sellPrice.IsZero() {
|
if s.Environment.IsBackTesting() {
|
||||||
if s.bottomPrice.IsZero() || s.bottomPrice.Compare(kline.Low) > 0 {
|
buyOrderTPSL(kline.High)
|
||||||
s.bottomPrice = kline.Low
|
sellOrderTPSL(kline.Low)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
takeProfit := false
|
|
||||||
peakBack := s.peakPrice
|
|
||||||
bottomBack := s.bottomPrice
|
|
||||||
if !baseBalance.IsZero() && !buyPrice.IsZero() {
|
|
||||||
|
|
||||||
// TP
|
|
||||||
if !atrx2.IsZero() && s.peakPrice.Sub(atrx2).Compare(lastPrice) >= 0 &&
|
|
||||||
lastPrice.Compare(buyPrice) > 0 {
|
|
||||||
sellall = true
|
|
||||||
s.peakPrice = fixedpoint.Zero
|
|
||||||
takeProfit = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// SL
|
|
||||||
if buyPrice.Sub(lastPrice).Div(buyPrice).Compare(s.Stoploss) > 0 ||
|
|
||||||
(!atrx2.IsZero() && buyPrice.Sub(atrx2).Compare(lastPrice) >= 0) {
|
|
||||||
sellall = true
|
|
||||||
s.peakPrice = fixedpoint.Zero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !quoteBalance.IsZero() && !sellPrice.IsZero() && !s.DisableShortStop {
|
|
||||||
// TP
|
|
||||||
if !atrx2.IsZero() && s.bottomPrice.Add(atrx2).Compare(lastPrice) >= 0 &&
|
|
||||||
lastPrice.Compare(sellPrice) < 0 {
|
|
||||||
buyall = true
|
|
||||||
s.bottomPrice = fixedpoint.Zero
|
|
||||||
takeProfit = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// SL
|
|
||||||
if (!atrx2.IsZero() && sellPrice.Add(atrx2).Compare(lastPrice) <= 0) ||
|
|
||||||
lastPrice.Sub(sellPrice).Div(sellPrice).Compare(s.Stoploss) > 0 {
|
|
||||||
buyall = true
|
|
||||||
s.bottomPrice = fixedpoint.Zero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sellall {
|
|
||||||
order := types.SubmitOrder{
|
|
||||||
Symbol: s.Symbol,
|
|
||||||
Side: types.SideTypeSell,
|
|
||||||
Type: types.OrderTypeMarket,
|
|
||||||
Market: s.Market,
|
|
||||||
Quantity: baseBalance,
|
|
||||||
}
|
|
||||||
if s.validateOrder(&order) {
|
|
||||||
if takeProfit {
|
|
||||||
log.Errorf("takeprofit sell at %v, avg %v, h: %v, atrx2: %v, timestamp: %s", lastPrice, buyPrice, peakBack, atrx2, kline.StartTime)
|
|
||||||
} else {
|
|
||||||
log.Errorf("stoploss sell at %v, avg %v, h: %v, atrx2: %v, timestamp %s", lastPrice, buyPrice, peakBack, atrx2, kline.StartTime)
|
|
||||||
}
|
|
||||||
createdOrders, err := orderExecutor.SubmitOrders(ctx, order)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Errorf("cannot place order")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Infof("stoploss sold order %v", createdOrders)
|
|
||||||
s.tradeCollector.Process()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if buyall {
|
|
||||||
totalQuantity := quoteBalance.Div(lastPrice)
|
|
||||||
order := types.SubmitOrder{
|
|
||||||
Symbol: kline.Symbol,
|
|
||||||
Side: types.SideTypeBuy,
|
|
||||||
Type: types.OrderTypeMarket,
|
|
||||||
Quantity: totalQuantity,
|
|
||||||
Market: s.Market,
|
|
||||||
}
|
|
||||||
if s.validateOrder(&order) {
|
|
||||||
if takeProfit {
|
|
||||||
log.Errorf("takeprofit buy at %v, avg %v, l: %v, atrx2: %v, timestamp: %s", lastPrice, sellPrice, bottomBack, atrx2, kline.StartTime)
|
|
||||||
} else {
|
|
||||||
log.Errorf("stoploss buy at %v, avg %v, l: %v, atrx2: %v, timestamp: %s", lastPrice, sellPrice, bottomBack, atrx2, kline.StartTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
createdOrders, err := orderExecutor.SubmitOrders(ctx, order)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Errorf("cannot place order")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Infof("stoploss bought order %v", createdOrders)
|
|
||||||
s.tradeCollector.Process()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -718,10 +790,12 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
// kline downthrough ma5, ma50 trend down, and ewo < threshold
|
// kline downthrough ma5, ma50 trend down, and ewo < threshold
|
||||||
IsBear := !bull && breakDown && s.ewo.Last() <= mean-2*std
|
IsBear := !bull && breakDown && s.ewo.Last() <= mean-2*std
|
||||||
|
|
||||||
log.Infof("IsBull: %v, bull: %v, longSignal[1]: %v, shortSignal: %v",
|
if !s.Environment.IsBackTesting() {
|
||||||
IsBull, bull, longSignal.Index(1), shortSignal.Last())
|
log.Infof("IsBull: %v, bull: %v, longSignal[1]: %v, shortSignal: %v",
|
||||||
log.Infof("IsBear: %v, bear: %v, shortSignal[1]: %v, longSignal: %v",
|
IsBull, bull, longSignal.Index(1), shortSignal.Last())
|
||||||
IsBear, !bull, shortSignal.Index(1), longSignal.Last())
|
log.Infof("IsBear: %v, bear: %v, shortSignal[1]: %v, longSignal: %v",
|
||||||
|
IsBear, !bull, shortSignal.Index(1), longSignal.Last())
|
||||||
|
}
|
||||||
|
|
||||||
var orders []types.SubmitOrder
|
var orders []types.SubmitOrder
|
||||||
var price fixedpoint.Value
|
var price fixedpoint.Value
|
||||||
|
|
Loading…
Reference in New Issue
Block a user