mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 00:05:15 +00:00
basic interaction parser
This commit is contained in:
parent
10ed50fbe2
commit
7053802041
32
doc/strategy/interaction.md
Normal file
32
doc/strategy/interaction.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
# Interaction
|
||||
|
||||
In your strategy, you can register your messenger interaction by commands.
|
||||
|
||||
|
||||
```
|
||||
package mymaker
|
||||
|
||||
import (
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
bbgo.RegisterInteraction(&MyInteraction{})
|
||||
}
|
||||
|
||||
type MyInteraction struct {}
|
||||
|
||||
func (m *MyInteraction) Commands(interact bbgo.Interact) {
|
||||
interact.Command("closePosition", func(w bbgo.InteractWriter, symbol string, percentage float64) {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
type Strategy struct {}
|
||||
```
|
||||
|
||||
|
||||
The interaction engine parses the command from the messenger software programs like Telegram or Slack.
|
||||
And then pass the arguments to the command handler defined in the strategy.
|
||||
|
106
pkg/bbgo/interact.go
Normal file
106
pkg/bbgo/interact.go
Normal file
|
@ -0,0 +1,106 @@
|
|||
package bbgo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"gopkg.in/tucnak/telebot.v2"
|
||||
)
|
||||
|
||||
// Interact implements the interaction between bot and message software.
|
||||
type Interact struct {
|
||||
Commands map[string]func()
|
||||
}
|
||||
|
||||
func (i *Interact) HandleTelegramMessage(msg *telebot.Message) {
|
||||
|
||||
}
|
||||
|
||||
func parseCommand(text string) (args []string, err error) {
|
||||
src := []byte(text)
|
||||
|
||||
// Initialize the scanner.
|
||||
var errHandler scanner.ErrorHandler = func(pos token.Position, msg string) {
|
||||
err = errors.New(msg)
|
||||
}
|
||||
|
||||
var s scanner.Scanner
|
||||
fset := token.NewFileSet() // positions are relative to fset
|
||||
file := fset.AddFile("", fset.Base(), len(src)) // register input "file"
|
||||
s.Init(file, src, errHandler, 0)
|
||||
|
||||
// Repeated calls to Scan yield the token sequence found in the input.
|
||||
for {
|
||||
_, tok, lit := s.Scan()
|
||||
if tok == token.EOF {
|
||||
break
|
||||
}
|
||||
|
||||
// we are not using the token type right now, but we will use them later
|
||||
args = append(args, lit)
|
||||
}
|
||||
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func parseFuncArgsAndCall(f interface{}, args []string) error {
|
||||
fv := reflect.ValueOf(f)
|
||||
ft := reflect.TypeOf(f)
|
||||
|
||||
var rArgs []reflect.Value
|
||||
for i := 0; i < ft.NumIn(); i++ {
|
||||
at := ft.In(i)
|
||||
|
||||
switch k := at.Kind(); k {
|
||||
|
||||
case reflect.String:
|
||||
av := reflect.ValueOf(args[i])
|
||||
rArgs = append(rArgs, av)
|
||||
|
||||
case reflect.Bool:
|
||||
bv, err := strconv.ParseBool(args[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
av := reflect.ValueOf(bv)
|
||||
rArgs = append(rArgs, av)
|
||||
|
||||
case reflect.Int64:
|
||||
nf, err := strconv.ParseInt(args[i], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
av := reflect.ValueOf(nf)
|
||||
rArgs = append(rArgs, av)
|
||||
|
||||
case reflect.Float64:
|
||||
nf, err := strconv.ParseFloat(args[i], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
av := reflect.ValueOf(nf)
|
||||
rArgs = append(rArgs, av)
|
||||
}
|
||||
}
|
||||
|
||||
out := fv.Call(rArgs)
|
||||
if ft.NumOut() > 0 {
|
||||
outType := ft.Out(0)
|
||||
switch outType.Kind() {
|
||||
case reflect.Interface:
|
||||
o := out[0].Interface()
|
||||
switch ov := o.(type) {
|
||||
case error:
|
||||
return ov
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
35
pkg/bbgo/interact_test.go
Normal file
35
pkg/bbgo/interact_test.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
package bbgo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_parseFuncArgsAndCall_NoErrorFunction(t *testing.T) {
|
||||
noErrorFunc := func(a string, b float64, c bool) error {
|
||||
assert.Equal(t, "BTCUSDT", a)
|
||||
assert.Equal(t, 0.123, b)
|
||||
assert.Equal(t, true, c)
|
||||
return nil
|
||||
}
|
||||
|
||||
err := parseFuncArgsAndCall(noErrorFunc, []string{"BTCUSDT", "0.123", "true"})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_parseFuncArgsAndCall_ErrorFunction(t *testing.T) {
|
||||
errorFunc := func(a string, b float64) error {
|
||||
return errors.New("error")
|
||||
}
|
||||
|
||||
err := parseFuncArgsAndCall(errorFunc, []string{"BTCUSDT", "0.123"})
|
||||
assert.Error(t, err)
|
||||
|
||||
}
|
||||
|
||||
func Test_parseCommand(t *testing.T) {
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user