Merge pull request #853 from zenixls2/feature/smartcancel_drift

feature: add smart cancel to drift
This commit is contained in:
Yo-An Lin 2022-08-09 16:23:33 +08:00 committed by GitHub
commit 55b4edc595
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 899 additions and 219 deletions

View File

@ -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;
}
}

View File

@ -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]

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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 {

View File

@ -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)
}
}

View File

@ -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,

View File

@ -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

View File

@ -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),
})
}

View File

@ -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,