implement buyandhold strategy to test the api design

This commit is contained in:
c9s 2020-10-13 16:17:07 +08:00
parent d1b618850d
commit ec23266cc2
3 changed files with 67 additions and 19 deletions

View File

@ -14,6 +14,13 @@ type Account struct {
Balances map[string]types.Balance
}
func (a *Account) Balance(currency string) (balance types.Balance, ok bool) {
a.Lock()
balance, ok = a.Balances[currency]
a.Unlock()
return balance, ok
}
func (a *Account) handleBalanceUpdates(balances map[string]types.Balance) {
a.Lock()
defer a.Unlock()
@ -34,7 +41,7 @@ func (a *Account) Print() {
for _, balance := range a.Balances {
if util.NotZero(balance.Available) {
log.Infof("[trader] balance %s %f", balance.Currency, balance.Available)
log.Infof("account balance %s %f", balance.Currency, balance.Available)
}
}
}

View File

@ -2,42 +2,82 @@ package buyandhold
import (
"context"
"encoding/json"
"io/ioutil"
"math"
"github.com/c9s/bbgo/pkg/bbgo"
"github.com/c9s/bbgo/pkg/types"
"github.com/c9s/bbgo/pkg/util"
)
type Strategy struct {
symbol string
Symbol string `json:"symbol"`
Interval string `json:"interval"`
BaseQuantity float64 `json:"baseQuantity"`
MaxAssetQuantity float64 `json:"maxAssetQuantity"`
MinDropPercentage float64 `json:"minDropPercentage"`
}
func New(symbol string) *Strategy {
func LoadFile(filepath string) (*Strategy, error) {
o, err := ioutil.ReadFile(filepath)
if err != nil {
return nil, err
}
var strategy Strategy
err = json.Unmarshal(o, &strategy)
return &strategy, err
}
func New(symbol string, interval string, baseQuantity float64) *Strategy {
return &Strategy{
symbol: symbol,
Symbol: symbol,
Interval: interval,
BaseQuantity: baseQuantity,
MinDropPercentage: -0.08,
}
}
func (s *Strategy) SetMinDropPercentage(p float64) *Strategy {
s.MinDropPercentage = p
return s
}
func (s *Strategy) SetMaxAssetQuantity(q float64) *Strategy {
s.MaxAssetQuantity = q
return s
}
func (s *Strategy) Run(ctx context.Context, trader types.Trader, session *bbgo.ExchangeSession) error {
session.Subscribe(types.KLineChannel, s.symbol, types.SubscribeOptions{ Interval: "1h" })
session.Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: s.Interval})
session.Stream.OnKLineClosed(func(kline types.KLine) {
changePercentage := kline.GetChange() / kline.Open
// buy when price drops -10%
if changePercentage < -0.1 {
// buy when price drops -8%
if changePercentage < s.MinDropPercentage {
market, ok := session.Markets[s.Symbol]
if !ok {
return
}
baseBalance, ok := session.Account.Balance(market.BaseCurrency)
if ok {
// we hold too many
if util.NotZero(s.MaxAssetQuantity) && baseBalance.Available > s.MaxAssetQuantity {
return
}
}
trader.SubmitOrder(ctx, &types.SubmitOrder{
Symbol: kline.Symbol,
Side: types.SideTypeBuy,
Type: types.OrderTypeMarket,
Quantity: 1.0,
Symbol: kline.Symbol,
Side: types.SideTypeBuy,
Type: types.OrderTypeMarket,
Quantity: s.BaseQuantity * math.Abs(changePercentage),
})
}
})
return nil
}

View File

@ -69,11 +69,12 @@ var rootCmd = &cobra.Command{
environ.AddExchange(sessionID, exchange).Subscribe(types.KLineChannel, symbol, types.SubscribeOptions{})
trader := bbgo.NewTrader(environ)
trader.AttachStrategy(sessionID, buyandhold.New(symbol))
trader.Run(ctx)
trader.AttachStrategy(sessionID, buyandhold.New(symbol, "1h", 0.1))
// trader.AttachCrossExchangeStrategy(...)
err = trader.Run(ctx)
cmdutil.WaitForSignal(ctx, syscall.SIGINT, syscall.SIGTERM)
return nil
return err
},
}