mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
feature: ewo add draw function
This commit is contained in:
parent
81084ddea6
commit
ff7fd38372
|
@ -29,21 +29,26 @@ exchangeStrategies:
|
|||
stoploss: 0.15%
|
||||
windowATR: 14
|
||||
windowQuick: 3
|
||||
windowSlow: 19
|
||||
windowSlow: 13
|
||||
source: hl2
|
||||
pendingMinutes: 8
|
||||
|
||||
drawGraph: true
|
||||
graphIndicatorPath: "./indicator.png"
|
||||
graphPNLPath: "./pnl.png"
|
||||
graphCumPNLPath: "./cumpnl.png"
|
||||
|
||||
|
||||
# ActivationRatio should be increasing order
|
||||
# when farest price from entry goes over that ratio, start using the callback ratio accordingly to do trailingstop
|
||||
#trailingActivationRatio: [0.01, 0.016, 0.05]
|
||||
#trailingActivationRatio: [0.001, 0.0081, 0.022]
|
||||
trailingActivationRatio: [0.0006, 0.0008, 0.0012, 0.0017, 0.01]
|
||||
trailingActivationRatio: [0.0008, 0.0012, 0.0017, 0.01, 0.015]
|
||||
#trailingActivationRatio: []
|
||||
#trailingCallbackRate: []
|
||||
#trailingCallbackRate: [0.002, 0.01, 0.1]
|
||||
#trailingCallbackRate: [0.0004, 0.0009, 0.018]
|
||||
trailingCallbackRate: [0.0001, 0.0002, 0.0003, 0.0006, 0.0049]
|
||||
trailingCallbackRate: [0.0002, 0.0003, 0.0006, 0.0049, 0.006]
|
||||
|
||||
#exits:
|
||||
# - roiStopLoss:
|
||||
|
|
|
@ -1,10 +1,53 @@
|
|||
package elliottwave
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/interact"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
"github.com/wcharczuk/go-chart/v2"
|
||||
)
|
||||
|
||||
func (s *Strategy) InitDrawCommands(store *bbgo.SerialMarketDataStore, profit, cumProfit types.Series) {
|
||||
bbgo.RegisterCommand("/draw", "Draw Indicators", func(reply interact.Reply) {
|
||||
canvas := s.DrawIndicators(store)
|
||||
if canvas == nil {
|
||||
reply.Message("cannot render indicators")
|
||||
return
|
||||
}
|
||||
var buffer bytes.Buffer
|
||||
if err := canvas.Render(chart.PNG, &buffer); err != nil {
|
||||
log.WithError(err).Errorf("cannot render indicators in ewo")
|
||||
reply.Message(fmt.Sprintf("[error] cannot render indicators in ewo: %v", err))
|
||||
return
|
||||
}
|
||||
bbgo.SendPhoto(&buffer)
|
||||
})
|
||||
bbgo.RegisterCommand("/pnl", "Draw PNL(%) per trade", func(reply interact.Reply) {
|
||||
canvas := s.DrawPNL(profit)
|
||||
var buffer bytes.Buffer
|
||||
if err := canvas.Render(chart.PNG, &buffer); err != nil {
|
||||
log.WithError(err).Errorf("cannot render pnl in drift")
|
||||
reply.Message(fmt.Sprintf("[error] cannot render pnl in ewo: %v", err))
|
||||
return
|
||||
}
|
||||
bbgo.SendPhoto(&buffer)
|
||||
})
|
||||
bbgo.RegisterCommand("/cumpnl", "Draw Cummulative PNL(Quote)", func(reply interact.Reply) {
|
||||
canvas := s.DrawCumPNL(cumProfit)
|
||||
var buffer bytes.Buffer
|
||||
if err := canvas.Render(chart.PNG, &buffer); err != nil {
|
||||
log.WithError(err).Errorf("cannot render cumpnl in drift")
|
||||
reply.Message(fmt.Sprintf("[error] canot render cumpnl in drift: %v", err))
|
||||
return
|
||||
}
|
||||
bbgo.SendPhoto(&buffer)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Strategy) DrawIndicators(store *bbgo.SerialMarketDataStore) *types.Canvas {
|
||||
klines, ok := store.KLinesOfInterval(types.Interval1m)
|
||||
if !ok {
|
||||
|
@ -18,18 +61,78 @@ func (s *Strategy) DrawIndicators(store *bbgo.SerialMarketDataStore) *types.Canv
|
|||
}
|
||||
log.Infof("draw indicators with %d data", Length)
|
||||
mean := s.priceLines.Mean(Length)
|
||||
high := s.priceLines.Highest(Length)
|
||||
low := s.priceLines.Lowest(Length)
|
||||
ehigh := types.Highest(s.ewo, Length)
|
||||
elow := types.Lowest(s.ewo, Length)
|
||||
canvas.Plot("ewo", types.Add(types.Mul(s.ewo, (high-low)/(ehigh-elow)), mean), time, Length)
|
||||
canvas.Plot("zero", types.NumberSeries(mean), time, Length)
|
||||
canvas.Plot("price", s.priceLines, time, Length)
|
||||
return canvas
|
||||
}
|
||||
|
||||
func (s *Strategy) DrawPNL(profit types.Series) *types.Canvas {
|
||||
return nil
|
||||
canvas := types.NewCanvas(s.InstanceID())
|
||||
length := profit.Length()
|
||||
log.Errorf("pnl Highest: %f, Lowest: %f", types.Highest(profit, length), types.Lowest(profit, length))
|
||||
canvas.PlotRaw("pnl %", profit, length)
|
||||
canvas.YAxis = chart.YAxis{
|
||||
ValueFormatter: func(v interface{}) string {
|
||||
if vf, isFloat := v.(float64); isFloat {
|
||||
return fmt.Sprintf("%.4f", vf)
|
||||
}
|
||||
return ""
|
||||
},
|
||||
}
|
||||
canvas.PlotRaw("1", types.NumberSeries(1), length)
|
||||
return canvas
|
||||
}
|
||||
|
||||
func (s *Strategy) DrawCumPNL(cumProfit types.Series) *types.Canvas {
|
||||
return nil
|
||||
canvas := types.NewCanvas(s.InstanceID())
|
||||
canvas.PlotRaw("cummulative pnl", cumProfit, cumProfit.Length())
|
||||
canvas.YAxis = chart.YAxis{
|
||||
ValueFormatter: func(v interface{}) string {
|
||||
if vf, isFloat := v.(float64); isFloat {
|
||||
return fmt.Sprintf("%.4f", vf)
|
||||
}
|
||||
return ""
|
||||
},
|
||||
}
|
||||
return canvas
|
||||
}
|
||||
|
||||
func (s *Strategy) Draw() {
|
||||
func (s *Strategy) Draw(store *bbgo.SerialMarketDataStore, profit, cumProfit types.Series) {
|
||||
canvas := s.DrawIndicators(store)
|
||||
f, err := os.Create(s.GraphIndicatorPath)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("cannot create on path " + s.GraphIndicatorPath)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
if err = canvas.Render(chart.PNG, f); err != nil {
|
||||
log.WithError(err).Errorf("cannot render elliottwave")
|
||||
}
|
||||
|
||||
canvas = s.DrawPNL(profit)
|
||||
f, err = os.Create(s.GraphPNLPath)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("cannot create on path " + s.GraphPNLPath)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
if err = canvas.Render(chart.PNG, f); err != nil {
|
||||
log.WithError(err).Errorf("cannot render pnl")
|
||||
return
|
||||
}
|
||||
canvas = s.DrawCumPNL(cumProfit)
|
||||
f, err = os.Create(s.GraphCumPNLPath)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("cannot create on path " + s.GraphCumPNLPath)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
if err = canvas.Render(chart.PNG, f); err != nil {
|
||||
log.WithError(err).Errorf("cannot render cumpnl")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,12 +14,10 @@ import (
|
|||
"github.com/c9s/bbgo/pkg/datatype/floats"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/c9s/bbgo/pkg/indicator"
|
||||
"github.com/c9s/bbgo/pkg/interact"
|
||||
"github.com/c9s/bbgo/pkg/strategy"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
"github.com/c9s/bbgo/pkg/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/wcharczuk/go-chart/v2"
|
||||
)
|
||||
|
||||
const ID = "elliottwave"
|
||||
|
@ -51,6 +49,12 @@ type Strategy struct {
|
|||
WindowSlow int `json:"windowSlow"`
|
||||
PendingMinutes int `json:"pendingMinutes"`
|
||||
|
||||
// whether to draw graph or not by the end of backtest
|
||||
DrawGraph bool `json:"drawGraph"`
|
||||
GraphIndicatorPath string `json:"graphIndicatorPath"`
|
||||
GraphPNLPath string `json:"graphPNLPath"`
|
||||
GraphCumPNLPath string `json:"graphCumPNLPath"`
|
||||
|
||||
*bbgo.Environment
|
||||
*bbgo.GeneralOrderExecutor
|
||||
*types.Position `persistence:"position"`
|
||||
|
@ -347,24 +351,11 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
if !ok {
|
||||
panic("cannot get 1m history")
|
||||
}
|
||||
bbgo.RegisterCommand("/draw", "Draw Indicators", func(reply interact.Reply) {
|
||||
canvas := s.DrawIndicators(store)
|
||||
if canvas == nil {
|
||||
reply.Message("cannot render indicators")
|
||||
return
|
||||
}
|
||||
var buffer bytes.Buffer
|
||||
if err := canvas.Render(chart.PNG, &buffer); err != nil {
|
||||
log.WithError(err).Errorf("cannot render indicators in ewo")
|
||||
reply.Message(fmt.Sprintf("[error] cannot render indicators in ewo: %v", err))
|
||||
return
|
||||
}
|
||||
bbgo.SendPhoto(&buffer)
|
||||
})
|
||||
if err := s.initIndicators(store); err != nil {
|
||||
log.WithError(err).Errorf("initIndicator failed")
|
||||
return nil
|
||||
}
|
||||
s.InitDrawCommands(store, &profit, &cumProfit)
|
||||
store.OnKLineClosed(func(kline types.KLine) {
|
||||
s.minutesCounter = int(kline.StartTime.Time().Sub(s.startTime).Minutes())
|
||||
if kline.Interval == types.Interval1m {
|
||||
|
@ -381,6 +372,9 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
|||
}
|
||||
fmt.Fprintln(&buffer, s.TradeStats.BriefString())
|
||||
os.Stdout.Write(buffer.Bytes())
|
||||
if s.DrawGraph {
|
||||
s.Draw(store, &profit, &cumProfit)
|
||||
}
|
||||
wg.Done()
|
||||
})
|
||||
return nil
|
||||
|
@ -442,12 +436,13 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
|||
|
||||
s.smartCancel(ctx, pricef)
|
||||
|
||||
atr := s.atr.Last()
|
||||
ewo := types.Array(s.ewo, 3)
|
||||
shortCondition := ewo[0] < ewo[1] && ewo[1] > ewo[2] || s.sellPrice == 0 && ewo[0] < ewo[1] && ewo[1] < ewo[2]
|
||||
longCondition := ewo[0] > ewo[1] && ewo[1] < ewo[2] || s.buyPrice == 0 && ewo[0] > ewo[1] && ewo[1] > ewo[2]
|
||||
|
||||
exitShortCondition := s.sellPrice > 0 && !shortCondition && s.sellPrice*(1.+stoploss) <= highf || s.trailingCheck(highf, "short")
|
||||
exitLongCondition := s.buyPrice > 0 && !longCondition && s.buyPrice*(1.-stoploss) >= lowf || s.trailingCheck(lowf, "long")
|
||||
exitShortCondition := s.sellPrice > 0 && !shortCondition && s.sellPrice*(1.+stoploss) <= highf || s.sellPrice+atr <= sourcef || s.trailingCheck(highf, "short")
|
||||
exitLongCondition := s.buyPrice > 0 && !longCondition && s.buyPrice*(1.-stoploss) >= lowf || s.buyPrice-atr >= sourcef || s.trailingCheck(lowf, "long")
|
||||
|
||||
if exitShortCondition || exitLongCondition {
|
||||
if err := s.GeneralOrderExecutor.GracefulCancel(ctx); err != nil {
|
||||
|
|
Loading…
Reference in New Issue
Block a user