mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 08:15:15 +00:00
implement buyandhold strategy to test the api design
This commit is contained in:
parent
d1b618850d
commit
ec23266cc2
|
@ -14,6 +14,13 @@ type Account struct {
|
||||||
Balances map[string]types.Balance
|
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) {
|
func (a *Account) handleBalanceUpdates(balances map[string]types.Balance) {
|
||||||
a.Lock()
|
a.Lock()
|
||||||
defer a.Unlock()
|
defer a.Unlock()
|
||||||
|
@ -34,7 +41,7 @@ func (a *Account) Print() {
|
||||||
|
|
||||||
for _, balance := range a.Balances {
|
for _, balance := range a.Balances {
|
||||||
if util.NotZero(balance.Available) {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,42 +2,82 @@ package buyandhold
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
"github.com/c9s/bbgo/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Strategy struct {
|
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) {
|
||||||
return &Strategy{
|
o, err := ioutil.ReadFile(filepath)
|
||||||
symbol: symbol,
|
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,
|
||||||
|
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 {
|
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) {
|
session.Stream.OnKLineClosed(func(kline types.KLine) {
|
||||||
changePercentage := kline.GetChange() / kline.Open
|
changePercentage := kline.GetChange() / kline.Open
|
||||||
|
|
||||||
// buy when price drops -10%
|
// buy when price drops -8%
|
||||||
if changePercentage < -0.1 {
|
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{
|
trader.SubmitOrder(ctx, &types.SubmitOrder{
|
||||||
Symbol: kline.Symbol,
|
Symbol: kline.Symbol,
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
Type: types.OrderTypeMarket,
|
Type: types.OrderTypeMarket,
|
||||||
Quantity: 1.0,
|
Quantity: s.BaseQuantity * math.Abs(changePercentage),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -69,11 +69,12 @@ var rootCmd = &cobra.Command{
|
||||||
environ.AddExchange(sessionID, exchange).Subscribe(types.KLineChannel, symbol, types.SubscribeOptions{})
|
environ.AddExchange(sessionID, exchange).Subscribe(types.KLineChannel, symbol, types.SubscribeOptions{})
|
||||||
|
|
||||||
trader := bbgo.NewTrader(environ)
|
trader := bbgo.NewTrader(environ)
|
||||||
trader.AttachStrategy(sessionID, buyandhold.New(symbol))
|
trader.AttachStrategy(sessionID, buyandhold.New(symbol, "1h", 0.1))
|
||||||
trader.Run(ctx)
|
// trader.AttachCrossExchangeStrategy(...)
|
||||||
|
err = trader.Run(ctx)
|
||||||
|
|
||||||
cmdutil.WaitForSignal(ctx, syscall.SIGINT, syscall.SIGTERM)
|
cmdutil.WaitForSignal(ctx, syscall.SIGINT, syscall.SIGTERM)
|
||||||
return nil
|
return err
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user