mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
Merge pull request #853 from zenixls2/feature/smartcancel_drift
feature: add smart cancel to drift
This commit is contained in:
commit
55b4edc595
|
@ -71,7 +71,7 @@ const parseOrder = () => {
|
|||
case "update_time":
|
||||
case "creation_time":
|
||||
case "time":
|
||||
d[key] = new Date(d[key]);
|
||||
d[key] = moment(d[key], 'dddd, DD MMM YYYY h:mm:ss').toDate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,12 +35,21 @@ exchangeStrategies:
|
|||
takeProfitFactor: 6
|
||||
profitFactorWindow: 8
|
||||
noTrailingStopLoss: false
|
||||
trailingStopLossType: kline
|
||||
# stddev on high/low-source
|
||||
hlVarianceMultiplier: 0.22
|
||||
hlVarianceMultiplier: 0.23
|
||||
hlRangeWindow: 5
|
||||
smootherWindow: 2
|
||||
fisherTransformWindow: 8
|
||||
smootherWindow: 1
|
||||
fisherTransformWindow: 9
|
||||
atrWindow: 14
|
||||
# orders not been traded will be canceled after `pendingMinutes` minutes
|
||||
pendingMinutes: 4
|
||||
noRebalance: true
|
||||
trendWindow: 12
|
||||
rebalanceFilter: 1.5
|
||||
|
||||
trailingActivationRatio: [0.008, 0.015]
|
||||
trailingCallbackRate: [0.002, 0.001]
|
||||
|
||||
generateGraph: true
|
||||
graphPNLDeductFee: true
|
||||
|
@ -79,7 +88,7 @@ sync:
|
|||
|
||||
backtest:
|
||||
startTime: "2022-01-01"
|
||||
endTime: "2022-07-29"
|
||||
endTime: "2022-07-30"
|
||||
symbols:
|
||||
- ETHBUSD
|
||||
sessions: [binance]
|
||||
|
|
|
@ -24,7 +24,7 @@ exchangeStrategies:
|
|||
- on: binance
|
||||
drift:
|
||||
canvasPath: "./output.png"
|
||||
symbol: BTCBUSD
|
||||
symbol: BTCUSDT
|
||||
# kline interval for indicators
|
||||
interval: 15m
|
||||
window: 2
|
||||
|
@ -32,15 +32,28 @@ exchangeStrategies:
|
|||
source: close
|
||||
predictOffset: 2
|
||||
noTrailingStopLoss: false
|
||||
trailingStopLossType: kline
|
||||
# stddev on high/low-source
|
||||
hlVarianceMultiplier: 0.22
|
||||
hlVarianceMultiplier: 0.23
|
||||
hlRangeWindow: 5
|
||||
smootherWindow: 2
|
||||
smootherWindow: 1
|
||||
fisherTransformWindow: 9
|
||||
# the init value of takeProfitFactor Series, the coefficient of ATR as TP
|
||||
takeProfitFactor: 6
|
||||
profitFactorWindow: 8
|
||||
atrWindow: 14
|
||||
takeProfitFactor: 1.2
|
||||
profitFactorWindow: 5
|
||||
atrWindow: 12
|
||||
# orders not been traded will be canceled after `pendingMinutes` minutes
|
||||
pendingMinutes: 3
|
||||
noRebalance: true
|
||||
trendWindow: 12
|
||||
rebalanceFilter: 3
|
||||
|
||||
# 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.007, 0.015, 0.02, 0.05]
|
||||
trailingActivationRatio: [0.007, 0.011]
|
||||
#trailingCallbackRate: [0.005, 0.003, 0.002, 0.001]
|
||||
trailingCallbackRate: [0.002, 0.001]
|
||||
|
||||
generateGraph: true
|
||||
graphPNLDeductFee: true
|
||||
|
@ -100,13 +113,13 @@ sync:
|
|||
sessions:
|
||||
- binance
|
||||
symbols:
|
||||
- BTCBUSD
|
||||
- BTCUSDT
|
||||
|
||||
backtest:
|
||||
startTime: "2022-01-01"
|
||||
endTime: "2022-07-29"
|
||||
endTime: "2022-07-26"
|
||||
symbols:
|
||||
- BTCBUSD
|
||||
- BTCUSDT
|
||||
sessions: [binance]
|
||||
accounts:
|
||||
binance:
|
||||
|
@ -114,4 +127,4 @@ backtest:
|
|||
takerFeeRate: 0.00075
|
||||
balances:
|
||||
BTC: 1
|
||||
BUSD: 5000.0
|
||||
USDT: 5000.0
|
||||
|
|
5
go.mod
5
go.mod
|
@ -42,7 +42,7 @@ require (
|
|||
github.com/spf13/cobra v1.1.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.7.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stretchr/testify v1.7.4
|
||||
github.com/valyala/fastjson v1.5.1
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0
|
||||
github.com/webview/webview v0.0.0-20210216142346-e0bfdf0e5d90
|
||||
|
@ -83,6 +83,7 @@ require (
|
|||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jedib0t/go-pretty/v6 v6.3.6 // indirect
|
||||
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
|
||||
github.com/json-iterator/go v1.1.11 // indirect
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
|
@ -93,7 +94,7 @@ require (
|
|||
github.com/magiconair/properties v1.8.4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.12 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
|
|
9
go.sum
9
go.sum
|
@ -352,6 +352,8 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f
|
|||
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jedib0t/go-pretty/v6 v6.3.6 h1:A6w2BuyPMtf7M82BGRBys9bAba2C26ZX9lrlrZ7uH6U=
|
||||
github.com/jedib0t/go-pretty/v6 v6.3.6/go.mod h1:MgmISkTWDSFu0xOqiZ0mKNntMQ2mDgOcwOkwBEkMDJI=
|
||||
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4=
|
||||
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
|
@ -442,6 +444,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
|||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
|
@ -503,6 +507,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
|
@ -599,6 +604,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
|
@ -608,6 +614,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
|||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM=
|
||||
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto=
|
||||
|
|
|
@ -51,6 +51,27 @@ func NewCoreInteraction(environment *Environment, trader *Trader) *CoreInteracti
|
|||
}
|
||||
}
|
||||
|
||||
type SimpleInteraction struct {
|
||||
Command string
|
||||
Description string
|
||||
F interface{}
|
||||
Cmd *interact.Command
|
||||
}
|
||||
|
||||
func (it *SimpleInteraction) Commands(i *interact.Interact) {
|
||||
it.Cmd = i.PrivateCommand(it.Command, it.Description, it.F)
|
||||
}
|
||||
|
||||
func RegisterCommand(command, desc string, f interface{}) *interact.Command {
|
||||
it := &SimpleInteraction{
|
||||
Command: command,
|
||||
Description: desc,
|
||||
F: f,
|
||||
}
|
||||
interact.AddCustomInteraction(it)
|
||||
return it.Cmd
|
||||
}
|
||||
|
||||
func getStrategySignatures(exchangeStrategies map[string]SingleExchangeStrategy) []string {
|
||||
var strategies []string
|
||||
for signature := range exchangeStrategies {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package bbgo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/util"
|
||||
|
@ -20,9 +22,19 @@ func NotifyTo(channel string, obj interface{}, args ...interface{}) {
|
|||
Notification.NotifyTo(channel, obj, args...)
|
||||
}
|
||||
|
||||
func SendPhoto(buffer *bytes.Buffer) {
|
||||
Notification.SendPhoto(buffer)
|
||||
}
|
||||
|
||||
func SendPhotoTo(channel string, buffer *bytes.Buffer) {
|
||||
Notification.SendPhotoTo(channel, buffer)
|
||||
}
|
||||
|
||||
type Notifier interface {
|
||||
NotifyTo(channel string, obj interface{}, args ...interface{})
|
||||
Notify(obj interface{}, args ...interface{})
|
||||
SendPhotoTo(channel string, buffer *bytes.Buffer)
|
||||
SendPhoto(buffer *bytes.Buffer)
|
||||
}
|
||||
|
||||
type NullNotifier struct{}
|
||||
|
@ -31,6 +43,10 @@ func (n *NullNotifier) NotifyTo(channel string, obj interface{}, args ...interfa
|
|||
|
||||
func (n *NullNotifier) Notify(obj interface{}, args ...interface{}) {}
|
||||
|
||||
func (n *NullNotifier) SendPhoto(buffer *bytes.Buffer) {}
|
||||
|
||||
func (n *NullNotifier) SendPhotoTo(channel string, buffer *bytes.Buffer) {}
|
||||
|
||||
type Notifiability struct {
|
||||
notifiers []Notifier
|
||||
SessionChannelRouter *PatternChannelRouter `json:"-"`
|
||||
|
@ -83,3 +99,15 @@ func (m *Notifiability) NotifyTo(channel string, obj interface{}, args ...interf
|
|||
n.NotifyTo(channel, obj, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Notifiability) SendPhoto(buffer *bytes.Buffer) {
|
||||
for _, n := range m.notifiers {
|
||||
n.SendPhoto(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Notifiability) SendPhotoTo(channel string, buffer *bytes.Buffer) {
|
||||
for _, n := range m.notifiers {
|
||||
n.SendPhotoTo(channel, buffer)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package slacknotifier
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
@ -150,6 +151,14 @@ func (n *Notifier) NotifyTo(channel string, obj interface{}, args ...interface{}
|
|||
}
|
||||
}
|
||||
|
||||
func (n *Notifier) SendPhoto(buffer *bytes.Buffer) {
|
||||
n.SendPhotoTo(n.channel, buffer)
|
||||
}
|
||||
|
||||
func (n *Notifier) SendPhotoTo(channel string, buffer *bytes.Buffer) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/*
|
||||
func (n *Notifier) NotifyTrade(trade *types.Trade) {
|
||||
_, _, err := n.client.PostMessageContext(context.Background(), n.TradeChannel,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package telegramnotifier
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
@ -129,6 +130,48 @@ func (n *Notifier) NotifyTo(channel string, obj interface{}, args ...interface{}
|
|||
}
|
||||
}
|
||||
|
||||
func (n *Notifier) SendPhoto(buffer *bytes.Buffer) {
|
||||
n.SendPhotoTo("", buffer)
|
||||
}
|
||||
|
||||
func photoFromBuffer(buffer *bytes.Buffer) telebot.InputMedia {
|
||||
reader := bytes.NewReader(buffer.Bytes())
|
||||
return &telebot.Photo{
|
||||
File: telebot.FromReader(reader),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Notifier) SendPhotoTo(channel string, buffer *bytes.Buffer) {
|
||||
if n.broadcast {
|
||||
if n.Subscribers == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for chatID := range n.Subscribers {
|
||||
chat, err := n.bot.ChatByID(strconv.FormatInt(chatID, 10))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("can not get chat by ID")
|
||||
continue
|
||||
}
|
||||
album := telebot.Album{
|
||||
photoFromBuffer(buffer),
|
||||
}
|
||||
if _, err := n.bot.SendAlbum(chat, album); err != nil {
|
||||
log.WithError(err).Error("failed to send message")
|
||||
}
|
||||
}
|
||||
} else if n.Chats != nil {
|
||||
for _, chat := range n.Chats {
|
||||
album := telebot.Album{
|
||||
photoFromBuffer(buffer),
|
||||
}
|
||||
if _, err := n.bot.SendAlbum(chat, album); err != nil {
|
||||
log.WithError(err).Error("telegram send error")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Notifier) AddChat(c *telebot.Chat) {
|
||||
if n.Chats == nil {
|
||||
n.Chats = make(map[int64]*telebot.Chat)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1192,16 +1192,35 @@ func NewCanvas(title string, intervals ...Interval) *Canvas {
|
|||
return out
|
||||
}
|
||||
|
||||
func (canvas *Canvas) Plot(tag string, a Series, endTime Time, length int) {
|
||||
func expand(a []float64, length int, defaultVal float64) []float64 {
|
||||
l := len(a)
|
||||
if l >= length {
|
||||
return a
|
||||
}
|
||||
for i := 0; i < length-l; i++ {
|
||||
a = append([]float64{defaultVal}, a...)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (canvas *Canvas) Plot(tag string, a Series, endTime Time, length int, intervals ...Interval) {
|
||||
var timeline []time.Time
|
||||
e := endTime.Time()
|
||||
if a.Length() == 0 {
|
||||
return
|
||||
}
|
||||
oldest := a.Index(a.Length() - 1)
|
||||
interval := canvas.Interval
|
||||
if len(intervals) > 0 {
|
||||
interval = intervals[0]
|
||||
}
|
||||
for i := length - 1; i >= 0; i-- {
|
||||
shiftedT := e.Add(-time.Duration(i*canvas.Interval.Minutes()) * time.Minute)
|
||||
shiftedT := e.Add(-time.Duration(i*interval.Minutes()) * time.Minute)
|
||||
timeline = append(timeline, shiftedT)
|
||||
}
|
||||
canvas.Series = append(canvas.Series, chart.TimeSeries{
|
||||
Name: tag,
|
||||
YValues: Reverse(a, length),
|
||||
YValues: expand(Reverse(a, length), length, oldest),
|
||||
XValues: timeline,
|
||||
})
|
||||
}
|
||||
|
@ -1211,10 +1230,14 @@ func (canvas *Canvas) PlotRaw(tag string, a Series, length int) {
|
|||
for i := 0; i < length; i++ {
|
||||
x = append(x, float64(i))
|
||||
}
|
||||
if a.Length() == 0 {
|
||||
return
|
||||
}
|
||||
oldest := a.Index(a.Length() - 1)
|
||||
canvas.Series = append(canvas.Series, chart.ContinuousSeries{
|
||||
Name: tag,
|
||||
XValues: x,
|
||||
YValues: Reverse(a, length),
|
||||
YValues: expand(Reverse(a, length), length, oldest),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -226,6 +226,8 @@ func (s *TradeStats) BriefString() string {
|
|||
GrossLoss: s.GrossLoss,
|
||||
LargestProfitTrade: s.LargestProfitTrade,
|
||||
LargestLossTrade: s.LargestLossTrade,
|
||||
AverageProfitTrade: s.AverageProfitTrade,
|
||||
AverageLossTrade: s.AverageLossTrade,
|
||||
ProfitFactor: s.ProfitFactor,
|
||||
TotalNetProfit: s.TotalNetProfit,
|
||||
IntervalProfits: s.IntervalProfits,
|
||||
|
|
Loading…
Reference in New Issue
Block a user