mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 06:53:52 +00:00
finalize swing strategy and fix trade reporter issue
This commit is contained in:
parent
c96845ff6a
commit
67446670ac
|
@ -5,25 +5,25 @@ imports:
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
slack:
|
slack:
|
||||||
defaultChannel: "#dev-bbgo"
|
defaultChannel: "dev-bbgo"
|
||||||
errorChannel: "#bbgo-error"
|
errorChannel: "bbgo-error"
|
||||||
|
|
||||||
# if you want to route channel by symbol
|
# if you want to route channel by symbol
|
||||||
symbolChannels:
|
symbolChannels:
|
||||||
"^BTC": "#btc"
|
"^BTC": "btc"
|
||||||
"^ETH": "#eth"
|
"^ETH": "eth"
|
||||||
|
|
||||||
# if you want to route channel by exchange session
|
# if you want to route channel by exchange session
|
||||||
sessionChannels:
|
sessionChannels:
|
||||||
max: "#bbgo-max"
|
max: "bbgo-max"
|
||||||
binance: "#bbgo-binance"
|
binance: "bbgo-binance"
|
||||||
|
|
||||||
# routing rules
|
# routing rules
|
||||||
routing:
|
routing:
|
||||||
trade: "$symbol"
|
trade: "$symbol"
|
||||||
order: "$symbol"
|
order: "$symbol"
|
||||||
submitOrder: "$session"
|
submitOrder: "$session"
|
||||||
pnL: "#bbgo-pnl"
|
pnL: "bbgo-pnl"
|
||||||
|
|
||||||
reportPnL:
|
reportPnL:
|
||||||
- averageCostBySymbols:
|
- averageCostBySymbols:
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
---
|
---
|
||||||
notifications:
|
notifications:
|
||||||
slack:
|
slack:
|
||||||
defaultChannel: "#dev-bbgo"
|
defaultChannel: "dev-bbgo"
|
||||||
errorChannel: "#bbgo-error"
|
errorChannel: "bbgo-error"
|
||||||
|
|
||||||
# if you want to route channel by symbol
|
# if you want to route channel by symbol
|
||||||
symbolChannels:
|
symbolChannels:
|
||||||
"^BTC": "#btc"
|
"^BTC": "btc"
|
||||||
"^ETH": "#eth"
|
"^ETH": "eth"
|
||||||
|
|
||||||
# object routing rules
|
# object routing rules
|
||||||
routing:
|
routing:
|
||||||
trade: "$symbol"
|
trade: "$symbol"
|
||||||
order: "$symbol"
|
order: "$symbol"
|
||||||
submitOrder: "$session" # not supported yet
|
submitOrder: "$session" # not supported yet
|
||||||
pnL: "#bbgo-pnl"
|
pnL: "bbgo-pnl"
|
||||||
|
|
||||||
sessions:
|
sessions:
|
||||||
binance:
|
binance:
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
---
|
---
|
||||||
notifications:
|
notifications:
|
||||||
slack:
|
slack:
|
||||||
defaultChannel: "#dev-bbgo"
|
defaultChannel: "dev-bbgo"
|
||||||
errorChannel: "#bbgo-error"
|
errorChannel: "bbgo-error"
|
||||||
|
|
||||||
# if you want to route channel by symbol
|
# if you want to route channel by symbol
|
||||||
symbolChannels:
|
symbolChannels:
|
||||||
"^BTC": "#btc"
|
"^BTC": "btc"
|
||||||
"^ETH": "#eth"
|
"^ETH": "eth"
|
||||||
"^BNB": "#bnb"
|
"^BNB": "bnb"
|
||||||
|
|
||||||
# object routing rules
|
# object routing rules
|
||||||
routing:
|
routing:
|
||||||
trade: "$symbol"
|
trade: "$symbol"
|
||||||
order: "$symbol"
|
order: "$symbol"
|
||||||
submitOrder: "$session" # not supported yet
|
submitOrder: "$session" # not supported yet
|
||||||
pnL: "#bbgo-pnl"
|
pnL: "bbgo-pnl"
|
||||||
|
|
||||||
sessions:
|
sessions:
|
||||||
binance:
|
binance:
|
||||||
|
|
|
@ -31,10 +31,10 @@ func injectField(rs reflect.Value, fieldName string, obj interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Infof("found %s in %T, injecting %T...", fieldName, rs.Type(), obj)
|
logrus.Infof("found %s in %s, injecting %T...", fieldName, rs.Type(), obj)
|
||||||
|
|
||||||
if !field.CanSet() {
|
if !field.CanSet() {
|
||||||
return errors.Errorf("field %s of %T can not be set", fieldName, rs.Type())
|
return errors.Errorf("field %s of %s can not be set", fieldName, rs.Type())
|
||||||
}
|
}
|
||||||
|
|
||||||
rv := reflect.ValueOf(obj)
|
rv := reflect.ValueOf(obj)
|
||||||
|
|
|
@ -79,8 +79,12 @@ func (store *MarketDataStore) handleKLineClosed(kline types.KLine) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *MarketDataStore) AddKLine(kline types.KLine) {
|
func (store *MarketDataStore) AddKLine(kline types.KLine) {
|
||||||
window := store.KLineWindows[kline.Interval]
|
window, ok := store.KLineWindows[kline.Interval]
|
||||||
window.Add(kline)
|
if !ok {
|
||||||
|
window = types.KLineWindow{kline}
|
||||||
|
} else {
|
||||||
|
window.Add(kline)
|
||||||
|
}
|
||||||
store.KLineWindows[kline.Interval] = window
|
store.KLineWindows[kline.Interval] = window
|
||||||
|
|
||||||
store.LastKLine = kline
|
store.LastKLine = kline
|
||||||
|
|
|
@ -142,15 +142,15 @@ func (router *ObjectChannelRouter) Route(obj interface{}) (channel string, ok bo
|
||||||
}
|
}
|
||||||
|
|
||||||
type TradeReporter struct {
|
type TradeReporter struct {
|
||||||
notifier Notifier
|
*Notifiability
|
||||||
|
|
||||||
channel string
|
channel string
|
||||||
channelRoutes map[*regexp.Regexp]string
|
channelRoutes map[*regexp.Regexp]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTradeReporter(notifier Notifier) *TradeReporter {
|
func NewTradeReporter(notifiability *Notifiability) *TradeReporter {
|
||||||
return &TradeReporter{
|
return &TradeReporter{
|
||||||
notifier: notifier,
|
Notifiability: notifiability,
|
||||||
channelRoutes: make(map[*regexp.Regexp]string),
|
channelRoutes: make(map[*regexp.Regexp]string),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,5 +182,5 @@ func (reporter *TradeReporter) Report(trade types.Trade) {
|
||||||
var channel = reporter.getChannel(trade.Symbol)
|
var channel = reporter.getChannel(trade.Symbol)
|
||||||
|
|
||||||
var text = util.Render(`:handshake: {{ .Symbol }} {{ .Side }} Trade Execution @ {{ .Price }}`, trade)
|
var text = util.Render(`:handshake: {{ .Symbol }} {{ .Side }} Trade Execution @ {{ .Price }}`, trade)
|
||||||
reporter.notifier.NotifyTo(channel, text, trade)
|
reporter.NotifyTo(channel, text, trade)
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,8 +86,6 @@ type ExchangeSession struct {
|
||||||
// standard indicators of each market
|
// standard indicators of each market
|
||||||
standardIndicatorSets map[string]*StandardIndicatorSet
|
standardIndicatorSets map[string]*StandardIndicatorSet
|
||||||
|
|
||||||
tradeReporter *TradeReporter
|
|
||||||
|
|
||||||
loadedSymbols map[string]struct{}
|
loadedSymbols map[string]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,11 +128,6 @@ func (session *ExchangeSession) Market(symbol string) (market types.Market, ok b
|
||||||
return market, ok
|
return market, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *ExchangeSession) ReportTrade(notifier Notifier) *TradeReporter {
|
|
||||||
session.tradeReporter = NewTradeReporter(notifier)
|
|
||||||
return session.tradeReporter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe save the subscription info, later it will be assigned to the stream
|
// Subscribe save the subscription info, later it will be assigned to the stream
|
||||||
func (session *ExchangeSession) Subscribe(channel types.Channel, symbol string, options types.SubscribeOptions) *ExchangeSession {
|
func (session *ExchangeSession) Subscribe(channel types.Channel, symbol string, options types.SubscribeOptions) *ExchangeSession {
|
||||||
sub := types.Subscription{
|
sub := types.Subscription{
|
||||||
|
|
|
@ -107,11 +107,7 @@ func (trader *Trader) Run(ctx context.Context) error {
|
||||||
// session based trade reporter
|
// session based trade reporter
|
||||||
for sessionName := range trader.environment.sessions {
|
for sessionName := range trader.environment.sessions {
|
||||||
var session = trader.environment.sessions[sessionName]
|
var session = trader.environment.sessions[sessionName]
|
||||||
if session.tradeReporter != nil {
|
if trader.tradeReporter != nil {
|
||||||
session.Stream.OnTrade(func(trade types.Trade) {
|
|
||||||
session.tradeReporter.Report(trade)
|
|
||||||
})
|
|
||||||
} else if trader.tradeReporter != nil {
|
|
||||||
session.Stream.OnTrade(func(trade types.Trade) {
|
session.Stream.OnTrade(func(trade types.Trade) {
|
||||||
trader.tradeReporter.Report(trade)
|
trader.tradeReporter.Report(trade)
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,6 +2,7 @@ package max
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
@ -54,7 +55,7 @@ func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) {
|
||||||
BaseCurrency: toGlobalCurrency(m.BaseUnit),
|
BaseCurrency: toGlobalCurrency(m.BaseUnit),
|
||||||
MinNotional: m.MinQuoteAmount,
|
MinNotional: m.MinQuoteAmount,
|
||||||
MinAmount: m.MinQuoteAmount,
|
MinAmount: m.MinQuoteAmount,
|
||||||
MinLot: m.MinBaseAmount,
|
MinLot: 1.0 / math.Pow10(m.BaseUnitPrecision), // make it like 0.0001
|
||||||
MinQuantity: m.MinBaseAmount,
|
MinQuantity: m.MinBaseAmount,
|
||||||
MaxQuantity: 10000.0,
|
MaxQuantity: 10000.0,
|
||||||
MinPrice: 0.1,
|
MinPrice: 0.1,
|
||||||
|
|
|
@ -40,6 +40,10 @@ func (n *Notifier) Notify(format string, args ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notifier) NotifyTo(channel, format string, args ...interface{}) {
|
func (n *Notifier) NotifyTo(channel, format string, args ...interface{}) {
|
||||||
|
if len(channel) == 0 {
|
||||||
|
channel = n.channel
|
||||||
|
}
|
||||||
|
|
||||||
var slackAttachments []slack.Attachment
|
var slackAttachments []slack.Attachment
|
||||||
var slackArgsOffset = -1
|
var slackArgsOffset = -1
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ type Strategy struct {
|
||||||
*bbgo.MarketDataStore
|
*bbgo.MarketDataStore
|
||||||
*types.Market
|
*types.Market
|
||||||
|
|
||||||
|
// OrderExecutor is an interface for submitting order
|
||||||
bbgo.OrderExecutor
|
bbgo.OrderExecutor
|
||||||
|
|
||||||
// These fields will be filled from the config file (it translates YAML to JSON)
|
// These fields will be filled from the config file (it translates YAML to JSON)
|
||||||
|
@ -116,7 +117,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
case 1:
|
case 1:
|
||||||
// if it goes up and it's above the moving average price, then we sell
|
// if it goes up and it's above the moving average price, then we sell
|
||||||
if closePrice > movingAveragePrice {
|
if closePrice > movingAveragePrice {
|
||||||
s.notify(":chart_with_upwards_trend: closePrice %f is above movingAveragePrice %f, submitting sell order", closePrice, movingAveragePrice)
|
s.notify(":chart_with_upwards_trend: closePrice %f is above movingAveragePrice %f, submitting SELL order", closePrice, movingAveragePrice)
|
||||||
|
|
||||||
_, err := orderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
_, err := orderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
||||||
Symbol: s.Symbol,
|
Symbol: s.Symbol,
|
||||||
|
@ -132,7 +133,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
case -1:
|
case -1:
|
||||||
// if it goes down and it's below the moving average price, then we buy
|
// if it goes down and it's below the moving average price, then we buy
|
||||||
if closePrice < movingAveragePrice {
|
if closePrice < movingAveragePrice {
|
||||||
s.notify(":chart_with_downwards_trend: closePrice %f is below movingAveragePrice %f, submitting buy order", closePrice, movingAveragePrice)
|
s.notify(":chart_with_downwards_trend: closePrice %f is below movingAveragePrice %f, submitting BUY order", closePrice, movingAveragePrice)
|
||||||
|
|
||||||
_, err := orderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
_, err := orderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
||||||
Symbol: s.Symbol,
|
Symbol: s.Symbol,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user