mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 00:35:15 +00:00
feature: add config dump / param dump / param modify for elliottwave, refactor param dump
This commit is contained in:
parent
8d92d43710
commit
b2875eedc5
96
pkg/dynamic/print_strategy.go
Normal file
96
pkg/dynamic/print_strategy.go
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
package dynamic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @param s: strategy object
|
||||||
|
// @param f: io.Writer used for writing the strategy dump
|
||||||
|
// @param seriesLength: if exist, the first value will be chosen to be the length of data from series to be printed out
|
||||||
|
// default to 1 when not exist or the value is invalid
|
||||||
|
func ParamDump(s interface{}, f io.Writer, seriesLength ...int) {
|
||||||
|
length := 1
|
||||||
|
if len(seriesLength) > 0 && seriesLength[0] > 0 {
|
||||||
|
length = seriesLength[0]
|
||||||
|
}
|
||||||
|
val := reflect.ValueOf(s)
|
||||||
|
if val.Type().Kind() == util.Pointer {
|
||||||
|
val = val.Elem()
|
||||||
|
}
|
||||||
|
for i := 0; i < val.Type().NumField(); i++ {
|
||||||
|
t := val.Type().Field(i)
|
||||||
|
if ig := t.Tag.Get("ignore"); ig == "true" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
field := val.Field(i)
|
||||||
|
if t.IsExported() || t.Anonymous || t.Type.Kind() == reflect.Func || t.Type.Kind() == reflect.Chan {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fieldName := t.Name
|
||||||
|
typeName := field.Type().String()
|
||||||
|
value := reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem()
|
||||||
|
isSeries := true
|
||||||
|
lastFunc := value.MethodByName("Last")
|
||||||
|
isSeries = isSeries && lastFunc.IsValid()
|
||||||
|
lengthFunc := value.MethodByName("Length")
|
||||||
|
isSeries = isSeries && lengthFunc.IsValid()
|
||||||
|
indexFunc := value.MethodByName("Index")
|
||||||
|
isSeries = isSeries && indexFunc.IsValid()
|
||||||
|
|
||||||
|
stringFunc := value.MethodByName("String")
|
||||||
|
canString := stringFunc.IsValid()
|
||||||
|
|
||||||
|
if isSeries {
|
||||||
|
l := int(lengthFunc.Call(nil)[0].Int())
|
||||||
|
if l >= length {
|
||||||
|
fmt.Fprintf(f, "%s: Series[..., %.4f", fieldName, indexFunc.Call([]reflect.Value{reflect.ValueOf(length - 1)})[0].Float())
|
||||||
|
for j := length - 2; j >= 0; j-- {
|
||||||
|
fmt.Fprintf(f, ", %.4f", indexFunc.Call([]reflect.Value{reflect.ValueOf(j)})[0].Float())
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "]\n")
|
||||||
|
} else if l > 0 {
|
||||||
|
fmt.Fprintf(f, "%s: Series[%.4f", fieldName, indexFunc.Call([]reflect.Value{reflect.ValueOf(l - 1)})[0].Float())
|
||||||
|
for j := l - 2; j >= 0; j-- {
|
||||||
|
fmt.Fprintf(f, ", %.4f", indexFunc.Call([]reflect.Value{reflect.ValueOf(j)})[0].Float())
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "]\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(f, "%s: Series[]\n", fieldName)
|
||||||
|
}
|
||||||
|
} else if canString {
|
||||||
|
fmt.Fprintf(f, "%s: %s\n", fieldName, stringFunc.Call(nil)[0].String())
|
||||||
|
} else if CanInt(field) {
|
||||||
|
fmt.Fprintf(f, "%s: %d\n", fieldName, field.Int())
|
||||||
|
} else if field.CanConvert(reflect.TypeOf(float64(0))) {
|
||||||
|
fmt.Fprintf(f, "%s: %.4f\n", fieldName, field.Float())
|
||||||
|
} else if field.CanInterface() {
|
||||||
|
fmt.Fprintf(f, "%s: %v", fieldName, field.Interface())
|
||||||
|
} else if field.Type().Kind() == reflect.Map {
|
||||||
|
fmt.Fprintf(f, "%s: {", fieldName)
|
||||||
|
iter := value.MapRange()
|
||||||
|
for iter.Next() {
|
||||||
|
k := iter.Key().Interface()
|
||||||
|
v := iter.Value().Interface()
|
||||||
|
fmt.Fprintf(f, "%v: %v, ", k, v)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "}\n")
|
||||||
|
} else if field.Type().Kind() == reflect.Slice {
|
||||||
|
fmt.Fprintf(f, "%s: [", fieldName)
|
||||||
|
l := field.Len()
|
||||||
|
if l > 0 {
|
||||||
|
fmt.Fprintf(f, "%v", field.Index(0))
|
||||||
|
}
|
||||||
|
for j := 1; j < field.Len(); j++ {
|
||||||
|
fmt.Fprintf(f, ", %v", field.Index(j))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "]\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(f, "%s(%s): %s\n", fieldName, typeName, field.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,101 +1,18 @@
|
||||||
package drift
|
package drift
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/jedib0t/go-pretty/v6/table"
|
"github.com/jedib0t/go-pretty/v6/table"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/dynamic"
|
"github.com/c9s/bbgo/pkg/dynamic"
|
||||||
style2 "github.com/c9s/bbgo/pkg/style"
|
"github.com/c9s/bbgo/pkg/style"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Strategy) ParamDump(f io.Writer, seriesLength ...int) {
|
|
||||||
length := 1
|
|
||||||
if len(seriesLength) > 0 && seriesLength[0] > 0 {
|
|
||||||
length = seriesLength[0]
|
|
||||||
}
|
|
||||||
val := reflect.ValueOf(s).Elem()
|
|
||||||
for i := 0; i < val.Type().NumField(); i++ {
|
|
||||||
t := val.Type().Field(i)
|
|
||||||
if ig := t.Tag.Get("ignore"); ig == "true" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
field := val.Field(i)
|
|
||||||
if t.IsExported() || t.Anonymous || t.Type.Kind() == reflect.Func || t.Type.Kind() == reflect.Chan {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fieldName := t.Name
|
|
||||||
typeName := field.Type().String()
|
|
||||||
log.Infof("fieldName %s typeName %s", fieldName, typeName)
|
|
||||||
value := reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem()
|
|
||||||
isSeries := true
|
|
||||||
lastFunc := value.MethodByName("Last")
|
|
||||||
isSeries = isSeries && lastFunc.IsValid()
|
|
||||||
lengthFunc := value.MethodByName("Length")
|
|
||||||
isSeries = isSeries && lengthFunc.IsValid()
|
|
||||||
indexFunc := value.MethodByName("Index")
|
|
||||||
isSeries = isSeries && indexFunc.IsValid()
|
|
||||||
|
|
||||||
stringFunc := value.MethodByName("String")
|
|
||||||
canString := stringFunc.IsValid()
|
|
||||||
|
|
||||||
if isSeries {
|
|
||||||
l := int(lengthFunc.Call(nil)[0].Int())
|
|
||||||
if l >= length {
|
|
||||||
fmt.Fprintf(f, "%s: Series[..., %.4f", fieldName, indexFunc.Call([]reflect.Value{reflect.ValueOf(length - 1)})[0].Float())
|
|
||||||
for j := length - 2; j >= 0; j-- {
|
|
||||||
fmt.Fprintf(f, ", %.4f", indexFunc.Call([]reflect.Value{reflect.ValueOf(j)})[0].Float())
|
|
||||||
}
|
|
||||||
fmt.Fprintf(f, "]\n")
|
|
||||||
} else if l > 0 {
|
|
||||||
fmt.Fprintf(f, "%s: Series[%.4f", fieldName, indexFunc.Call([]reflect.Value{reflect.ValueOf(l - 1)})[0].Float())
|
|
||||||
for j := l - 2; j >= 0; j-- {
|
|
||||||
fmt.Fprintf(f, ", %.4f", indexFunc.Call([]reflect.Value{reflect.ValueOf(j)})[0].Float())
|
|
||||||
}
|
|
||||||
fmt.Fprintf(f, "]\n")
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(f, "%s: Series[]\n", fieldName)
|
|
||||||
}
|
|
||||||
} else if canString {
|
|
||||||
fmt.Fprintf(f, "%s: %s\n", fieldName, stringFunc.Call(nil)[0].String())
|
|
||||||
} else if dynamic.CanInt(field) {
|
|
||||||
fmt.Fprintf(f, "%s: %d\n", fieldName, field.Int())
|
|
||||||
} else if field.CanConvert(reflect.TypeOf(float64(0))) {
|
|
||||||
fmt.Fprintf(f, "%s: %.4f\n", fieldName, field.Float())
|
|
||||||
} else if field.CanInterface() {
|
|
||||||
fmt.Fprintf(f, "%s: %v", fieldName, field.Interface())
|
|
||||||
} else if field.Type().Kind() == reflect.Map {
|
|
||||||
fmt.Fprintf(f, "%s: {", fieldName)
|
|
||||||
iter := value.MapRange()
|
|
||||||
for iter.Next() {
|
|
||||||
k := iter.Key().Interface()
|
|
||||||
v := iter.Value().Interface()
|
|
||||||
fmt.Fprintf(f, "%v: %v, ", k, v)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(f, "}\n")
|
|
||||||
} else if field.Type().Kind() == reflect.Slice {
|
|
||||||
fmt.Fprintf(f, "%s: [", fieldName)
|
|
||||||
l := field.Len()
|
|
||||||
if l > 0 {
|
|
||||||
fmt.Fprintf(f, "%v", field.Index(0))
|
|
||||||
}
|
|
||||||
for j := 1; j < field.Len(); j++ {
|
|
||||||
fmt.Fprintf(f, ", %v", field.Index(j))
|
|
||||||
}
|
|
||||||
fmt.Fprintf(f, "]\n")
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(f, "%s(%s): %s\n", fieldName, typeName, field.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Strategy) Print(f io.Writer, pretty bool, withColor ...bool) {
|
func (s *Strategy) Print(f io.Writer, pretty bool, withColor ...bool) {
|
||||||
var style *table.Style
|
var tableStyle *table.Style
|
||||||
if pretty {
|
if pretty {
|
||||||
style = style2.NewDefaultTableStyle()
|
tableStyle = style.NewDefaultTableStyle()
|
||||||
}
|
}
|
||||||
dynamic.PrintConfig(s, f, style, len(withColor) > 0 && withColor[0], dynamic.DefaultWhiteList()...)
|
dynamic.PrintConfig(s, f, tableStyle, len(withColor) > 0 && withColor[0], dynamic.DefaultWhiteList()...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
"github.com/c9s/bbgo/pkg/datatype/floats"
|
"github.com/c9s/bbgo/pkg/datatype/floats"
|
||||||
|
"github.com/c9s/bbgo/pkg/dynamic"
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/indicator"
|
"github.com/c9s/bbgo/pkg/indicator"
|
||||||
"github.com/c9s/bbgo/pkg/interact"
|
"github.com/c9s/bbgo/pkg/interact"
|
||||||
|
@ -148,11 +149,11 @@ func (s *Strategy) CurrentPosition() *types.Position {
|
||||||
return s.Position
|
return s.Position
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) ClosePosition(ctx context.Context, percentage fixedpoint.Value) bool {
|
func (s *Strategy) ClosePosition(ctx context.Context, percentage fixedpoint.Value) error {
|
||||||
order := s.p.NewMarketCloseOrder(percentage)
|
order := s.p.NewMarketCloseOrder(percentage)
|
||||||
if order == nil {
|
if order == nil {
|
||||||
s.positionLock.Unlock()
|
s.positionLock.Unlock()
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
order.Tag = "close"
|
order.Tag = "close"
|
||||||
order.TimeInForce = ""
|
order.TimeInForce = ""
|
||||||
|
@ -171,14 +172,14 @@ func (s *Strategy) ClosePosition(ctx context.Context, percentage fixedpoint.Valu
|
||||||
s.positionLock.Unlock()
|
s.positionLock.Unlock()
|
||||||
for {
|
for {
|
||||||
if s.Market.IsDustQuantity(order.Quantity, price) {
|
if s.Market.IsDustQuantity(order.Quantity, price) {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
_, err := s.GeneralOrderExecutor.SubmitOrders(ctx, *order)
|
_, err := s.GeneralOrderExecutor.SubmitOrders(ctx, *order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
order.Quantity = order.Quantity.Mul(fixedpoint.One.Sub(Delta))
|
order.Quantity = order.Quantity.Mul(fixedpoint.One.Sub(Delta))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,9 +384,8 @@ func (s *Strategy) initTickerFunctions(ctx context.Context) {
|
||||||
exitLongCondition := s.buyPrice > 0 && (s.buyPrice*(1.-stoploss) >= pricef ||
|
exitLongCondition := s.buyPrice > 0 && (s.buyPrice*(1.-stoploss) >= pricef ||
|
||||||
s.trailingCheck(pricef, "long"))
|
s.trailingCheck(pricef, "long"))
|
||||||
if exitShortCondition || exitLongCondition {
|
if exitShortCondition || exitLongCondition {
|
||||||
if s.ClosePosition(ctx, fixedpoint.One) {
|
s.ClosePosition(ctx, fixedpoint.One)
|
||||||
log.Infof("close position by orderbook changes")
|
log.Infof("close position by orderbook changes")
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
s.positionLock.Unlock()
|
s.positionLock.Unlock()
|
||||||
}
|
}
|
||||||
|
@ -993,9 +993,9 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
l, err := strconv.Atoi(length)
|
l, err := strconv.Atoi(length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.ParamDump(&buffer)
|
dynamic.ParamDump(s, &buffer)
|
||||||
} else {
|
} else {
|
||||||
s.ParamDump(&buffer, l)
|
dynamic.ParamDump(s, &buffer, l)
|
||||||
}
|
}
|
||||||
reply.Message(buffer.String())
|
reply.Message(buffer.String())
|
||||||
})
|
})
|
||||||
|
|
43
pkg/strategy/elliottwave/output.go
Normal file
43
pkg/strategy/elliottwave/output.go
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package elliottwave
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
"github.com/c9s/bbgo/pkg/dynamic"
|
||||||
|
"github.com/c9s/bbgo/pkg/interact"
|
||||||
|
"github.com/c9s/bbgo/pkg/style"
|
||||||
|
"github.com/jedib0t/go-pretty/v6/table"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Strategy) initOutputCommands() {
|
||||||
|
bbgo.RegisterCommand("/config", "Show latest config", func(reply interact.Reply) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
s.Print(&buffer, false)
|
||||||
|
reply.Message(buffer.String())
|
||||||
|
})
|
||||||
|
bbgo.RegisterCommand("/dump", "Dump internal params", func(reply interact.Reply) {
|
||||||
|
reply.Message("Please enter series output length:")
|
||||||
|
}).Next(func(length string, reply interact.Reply) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
l, err := strconv.Atoi(length)
|
||||||
|
if err != nil {
|
||||||
|
dynamic.ParamDump(s, &buffer)
|
||||||
|
} else {
|
||||||
|
dynamic.ParamDump(s, &buffer, l)
|
||||||
|
}
|
||||||
|
reply.Message(buffer.String())
|
||||||
|
})
|
||||||
|
|
||||||
|
bbgo.RegisterModifier(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Strategy) Print(f io.Writer, pretty bool, withColor ...bool) {
|
||||||
|
var tableStyle *table.Style
|
||||||
|
if pretty {
|
||||||
|
tableStyle = style.NewDefaultTableStyle()
|
||||||
|
}
|
||||||
|
dynamic.PrintConfig(s, f, tableStyle, len(withColor) > 0 && withColor[0], dynamic.DefaultWhiteList()...)
|
||||||
|
}
|
|
@ -36,17 +36,18 @@ type SourceFunc func(*types.KLine) fixedpoint.Value
|
||||||
type Strategy struct {
|
type Strategy struct {
|
||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol"`
|
||||||
|
|
||||||
|
bbgo.OpenPositionOptions
|
||||||
bbgo.StrategyController
|
bbgo.StrategyController
|
||||||
bbgo.SourceSelector
|
bbgo.SourceSelector
|
||||||
types.Market
|
types.Market
|
||||||
Session *bbgo.ExchangeSession
|
Session *bbgo.ExchangeSession
|
||||||
|
|
||||||
Interval types.Interval `json:"interval"`
|
Interval types.Interval `json:"interval"`
|
||||||
Stoploss fixedpoint.Value `json:"stoploss"`
|
Stoploss fixedpoint.Value `json:"stoploss" modifiable:"true"`
|
||||||
WindowATR int `json:"windowATR"`
|
WindowATR int `json:"windowATR"`
|
||||||
WindowQuick int `json:"windowQuick"`
|
WindowQuick int `json:"windowQuick"`
|
||||||
WindowSlow int `json:"windowSlow"`
|
WindowSlow int `json:"windowSlow"`
|
||||||
PendingMinutes int `json:"pendingMinutes"`
|
PendingMinutes int `json:"pendingMinutes" modifiable:"true"`
|
||||||
UseHeikinAshi bool `json:"useHeikinAshi"`
|
UseHeikinAshi bool `json:"useHeikinAshi"`
|
||||||
|
|
||||||
// whether to draw graph or not by the end of backtest
|
// whether to draw graph or not by the end of backtest
|
||||||
|
@ -80,8 +81,8 @@ type Strategy struct {
|
||||||
highestPrice float64 `persistence:"highest_price"`
|
highestPrice float64 `persistence:"highest_price"`
|
||||||
lowestPrice float64 `persistence:"lowest_price"`
|
lowestPrice float64 `persistence:"lowest_price"`
|
||||||
|
|
||||||
TrailingCallbackRate []float64 `json:"trailingCallbackRate"`
|
TrailingCallbackRate []float64 `json:"trailingCallbackRate" modifiable:"true"`
|
||||||
TrailingActivationRatio []float64 `json:"trailingActivationRatio"`
|
TrailingActivationRatio []float64 `json:"trailingActivationRatio" modifiable:"true"`
|
||||||
ExitMethods bbgo.ExitMethodSet `json:"exits"`
|
ExitMethods bbgo.ExitMethodSet `json:"exits"`
|
||||||
|
|
||||||
midPrice fixedpoint.Value
|
midPrice fixedpoint.Value
|
||||||
|
@ -131,6 +132,7 @@ func (s *Strategy) ClosePosition(ctx context.Context, percentage fixedpoint.Valu
|
||||||
} else if order.Side == types.SideTypeSell && order.Quantity.Compare(baseBalance) > 0 {
|
} else if order.Side == types.SideTypeSell && order.Quantity.Compare(baseBalance) > 0 {
|
||||||
order.Quantity = baseBalance
|
order.Quantity = baseBalance
|
||||||
}
|
}
|
||||||
|
order.MarginSideEffect = types.SideEffectTypeAutoRepay
|
||||||
for {
|
for {
|
||||||
if s.Market.IsDustQuantity(order.Quantity, price) {
|
if s.Market.IsDustQuantity(order.Quantity, price) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -355,6 +357,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
s.TradeStats.SetIntervalProfitCollector(types.NewIntervalProfitCollector(types.Interval1d, startTime))
|
s.TradeStats.SetIntervalProfitCollector(types.NewIntervalProfitCollector(types.Interval1d, startTime))
|
||||||
s.TradeStats.SetIntervalProfitCollector(types.NewIntervalProfitCollector(types.Interval1w, startTime))
|
s.TradeStats.SetIntervalProfitCollector(types.NewIntervalProfitCollector(types.Interval1w, startTime))
|
||||||
|
|
||||||
|
s.initOutputCommands()
|
||||||
|
|
||||||
// event trigger order: s.Interval => Interval1m
|
// event trigger order: s.Interval => Interval1m
|
||||||
store, ok := session.SerialMarketDataStore(s.Symbol, []types.Interval{s.Interval, types.Interval1m})
|
store, ok := session.SerialMarketDataStore(s.Symbol, []types.Interval{s.Interval, types.Interval1m})
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -380,6 +384,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
fmt.Fprintf(&buffer, "%s\n", daypnl)
|
fmt.Fprintf(&buffer, "%s\n", daypnl)
|
||||||
}
|
}
|
||||||
fmt.Fprintln(&buffer, s.TradeStats.BriefString())
|
fmt.Fprintln(&buffer, s.TradeStats.BriefString())
|
||||||
|
s.Print(&buffer, true, true)
|
||||||
os.Stdout.Write(buffer.Bytes())
|
os.Stdout.Write(buffer.Bytes())
|
||||||
if s.DrawGraph {
|
if s.DrawGraph {
|
||||||
s.Draw(store, &profit, &cumProfit)
|
s.Draw(store, &profit, &cumProfit)
|
||||||
|
@ -491,33 +496,23 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
||||||
}
|
}
|
||||||
if source.Compare(price) > 0 {
|
if source.Compare(price) > 0 {
|
||||||
source = price
|
source = price
|
||||||
sourcef = source.Float64()
|
|
||||||
}
|
}
|
||||||
balances := s.GeneralOrderExecutor.Session().GetAccount().Balances()
|
opt := s.OpenPositionOptions
|
||||||
quoteBalance, ok := balances[s.Market.QuoteCurrency]
|
opt.Long = true
|
||||||
if !ok {
|
opt.Price = source
|
||||||
log.Errorf("unable to get quoteCurrency")
|
opt.Tags = []string{"long"}
|
||||||
return
|
log.Infof("source in long %v %v", source, price)
|
||||||
}
|
createdOrders, err := s.GeneralOrderExecutor.OpenPosition(ctx, opt)
|
||||||
if s.Market.IsDustQuantity(
|
|
||||||
quoteBalance.Available.Div(source), source) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
quantity := quoteBalance.Available.Div(source)
|
|
||||||
createdOrders, err := s.GeneralOrderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
|
||||||
Symbol: s.Symbol,
|
|
||||||
Side: types.SideTypeBuy,
|
|
||||||
Type: types.OrderTypeLimit,
|
|
||||||
Price: source,
|
|
||||||
Quantity: quantity,
|
|
||||||
Tag: "long",
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Errorf("cannot place buy order")
|
if _, ok := err.(types.ZeroAssetError); ok {
|
||||||
log.Errorf("%v %v %v", quoteBalance, source, kline)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.WithError(err).Errorf("cannot place buy order: %v %v", source, kline)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if createdOrders != nil {
|
||||||
s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter
|
s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if shortCondition && !bull {
|
if shortCondition && !bull {
|
||||||
|
@ -527,31 +522,23 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
||||||
}
|
}
|
||||||
if source.Compare(price) < 0 {
|
if source.Compare(price) < 0 {
|
||||||
source = price
|
source = price
|
||||||
sourcef = price.Float64()
|
|
||||||
}
|
}
|
||||||
balances := s.GeneralOrderExecutor.Session().GetAccount().Balances()
|
opt := s.OpenPositionOptions
|
||||||
baseBalance, ok := balances[s.Market.BaseCurrency]
|
opt.Short = true
|
||||||
if !ok {
|
opt.Price = source
|
||||||
log.Errorf("unable to get baseCurrency")
|
opt.Tags = []string{"short"}
|
||||||
return
|
log.Infof("source in short %v %v", source, price)
|
||||||
}
|
createdOrders, err := s.GeneralOrderExecutor.OpenPosition(ctx, opt)
|
||||||
if s.Market.IsDustQuantity(baseBalance.Available, source) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
quantity := baseBalance.Available
|
|
||||||
createdOrders, err := s.GeneralOrderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
|
||||||
Symbol: s.Symbol,
|
|
||||||
Side: types.SideTypeSell,
|
|
||||||
Type: types.OrderTypeLimit,
|
|
||||||
Price: source,
|
|
||||||
Quantity: quantity,
|
|
||||||
Tag: "short",
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Errorf("cannot place sell order")
|
if _, ok := err.(types.ZeroAssetError); ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.WithError(err).Errorf("cannot place sell order: %v %v", source, kline)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if createdOrders != nil {
|
||||||
s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter
|
s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user