mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 16:55:15 +00:00
commit
2e9f554f9e
|
@ -71,7 +71,7 @@ const parseOrder = () => {
|
||||||
case "update_time":
|
case "update_time":
|
||||||
case "creation_time":
|
case "creation_time":
|
||||||
case "time":
|
case "time":
|
||||||
d[key] = new Date(d[key]);
|
d[key] = moment(d[key], 'dddd, DD MMM YYYY h:mm:ss').toDate();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,16 +31,25 @@ exchangeStrategies:
|
||||||
stoploss: 0.3%
|
stoploss: 0.3%
|
||||||
source: close
|
source: close
|
||||||
predictOffset: 2
|
predictOffset: 2
|
||||||
# the init value of takeProfitFactor Series, position avg +- takeProfitFactor * atr as take profit price
|
|
||||||
takeProfitFactor: 6
|
|
||||||
profitFactorWindow: 8
|
|
||||||
noTrailingStopLoss: false
|
noTrailingStopLoss: false
|
||||||
|
trailingStopLossType: kline
|
||||||
# stddev on high/low-source
|
# stddev on high/low-source
|
||||||
hlVarianceMultiplier: 0.22
|
hlVarianceMultiplier: 0.23
|
||||||
hlRangeWindow: 5
|
hlRangeWindow: 5
|
||||||
smootherWindow: 2
|
window1m: 24
|
||||||
fisherTransformWindow: 8
|
smootherWindow1m: 24
|
||||||
|
fisherTransformWindow1m: 162
|
||||||
|
smootherWindow: 1
|
||||||
|
fisherTransformWindow: 9
|
||||||
atrWindow: 14
|
atrWindow: 14
|
||||||
|
# orders not been traded will be canceled after `pendingMinutes` minutes
|
||||||
|
pendingMinutes: 3
|
||||||
|
noRebalance: true
|
||||||
|
trendWindow: 12
|
||||||
|
rebalanceFilter: 1.5
|
||||||
|
|
||||||
|
trailingActivationRatio: [0.004]
|
||||||
|
trailingCallbackRate: [0.001]
|
||||||
|
|
||||||
generateGraph: true
|
generateGraph: true
|
||||||
graphPNLDeductFee: true
|
graphPNLDeductFee: true
|
||||||
|
@ -79,7 +88,7 @@ sync:
|
||||||
|
|
||||||
backtest:
|
backtest:
|
||||||
startTime: "2022-01-01"
|
startTime: "2022-01-01"
|
||||||
endTime: "2022-07-29"
|
endTime: "2022-08-30"
|
||||||
symbols:
|
symbols:
|
||||||
- ETHBUSD
|
- ETHBUSD
|
||||||
sessions: [binance]
|
sessions: [binance]
|
||||||
|
|
|
@ -24,7 +24,7 @@ exchangeStrategies:
|
||||||
- on: binance
|
- on: binance
|
||||||
drift:
|
drift:
|
||||||
canvasPath: "./output.png"
|
canvasPath: "./output.png"
|
||||||
symbol: BTCBUSD
|
symbol: BTCUSDT
|
||||||
# kline interval for indicators
|
# kline interval for indicators
|
||||||
interval: 15m
|
interval: 15m
|
||||||
window: 2
|
window: 2
|
||||||
|
@ -32,18 +32,33 @@ exchangeStrategies:
|
||||||
source: close
|
source: close
|
||||||
predictOffset: 2
|
predictOffset: 2
|
||||||
noTrailingStopLoss: false
|
noTrailingStopLoss: false
|
||||||
|
trailingStopLossType: kline
|
||||||
# stddev on high/low-source
|
# stddev on high/low-source
|
||||||
hlVarianceMultiplier: 0.22
|
hlVarianceMultiplier: 0.22
|
||||||
hlRangeWindow: 5
|
hlRangeWindow: 5
|
||||||
smootherWindow: 2
|
smootherWindow: 1
|
||||||
fisherTransformWindow: 9
|
fisherTransformWindow: 9
|
||||||
# the init value of takeProfitFactor Series, the coefficient of ATR as TP
|
window1m: 22
|
||||||
takeProfitFactor: 6
|
smootherWindow1m: 18
|
||||||
profitFactorWindow: 8
|
fisherTransformWindow1m: 162
|
||||||
atrWindow: 14
|
atrWindow: 14
|
||||||
|
# orders not been traded will be canceled after `pendingMinutes` minutes
|
||||||
|
pendingMinutes: 5
|
||||||
|
noRebalance: true
|
||||||
|
trendWindow: 576
|
||||||
|
rebalanceFilter: 0
|
||||||
|
|
||||||
|
# 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.0012, 0.002, 0.01, 0.016]
|
||||||
|
#trailingActivationRatio: []
|
||||||
|
#trailingCallbackRate: []
|
||||||
|
#trailingCallbackRate: [0.002, 0.01, 0.1]
|
||||||
|
trailingCallbackRate: [0.0004, 0.0008, 0.002, 0.01]
|
||||||
|
|
||||||
generateGraph: true
|
generateGraph: true
|
||||||
graphPNLDeductFee: true
|
graphPNLDeductFee: false
|
||||||
graphPNLPath: "./pnl.png"
|
graphPNLPath: "./pnl.png"
|
||||||
graphCumPNLPath: "./cumpnl.png"
|
graphCumPNLPath: "./cumpnl.png"
|
||||||
#exits:
|
#exits:
|
||||||
|
@ -100,18 +115,18 @@ sync:
|
||||||
sessions:
|
sessions:
|
||||||
- binance
|
- binance
|
||||||
symbols:
|
symbols:
|
||||||
- BTCBUSD
|
- BTCUSDT
|
||||||
|
|
||||||
backtest:
|
backtest:
|
||||||
startTime: "2022-01-01"
|
startTime: "2022-01-01"
|
||||||
endTime: "2022-07-29"
|
endTime: "2022-08-30"
|
||||||
symbols:
|
symbols:
|
||||||
- BTCBUSD
|
- BTCUSDT
|
||||||
sessions: [binance]
|
sessions: [binance]
|
||||||
accounts:
|
accounts:
|
||||||
binance:
|
binance:
|
||||||
makerFeeRate: 0.000
|
makerFeeRate: 0.000
|
||||||
takerFeeRate: 0.00075
|
#takerFeeRate: 0.000
|
||||||
balances:
|
balances:
|
||||||
BTC: 1
|
BTC: 1
|
||||||
BUSD: 5000.0
|
USDT: 5000
|
||||||
|
|
5
go.mod
5
go.mod
|
@ -25,6 +25,7 @@ require (
|
||||||
github.com/golang/mock v1.6.0
|
github.com/golang/mock v1.6.0
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/gorilla/websocket v1.5.0
|
github.com/gorilla/websocket v1.5.0
|
||||||
|
github.com/jedib0t/go-pretty/v6 v6.3.6
|
||||||
github.com/jmoiron/sqlx v1.3.4
|
github.com/jmoiron/sqlx v1.3.4
|
||||||
github.com/joho/godotenv v1.3.0
|
github.com/joho/godotenv v1.3.0
|
||||||
github.com/leekchan/accounting v0.0.0-20191218023648-17a4ce5f94d4
|
github.com/leekchan/accounting v0.0.0-20191218023648-17a4ce5f94d4
|
||||||
|
@ -43,7 +44,7 @@ require (
|
||||||
github.com/spf13/cobra v1.1.1
|
github.com/spf13/cobra v1.1.1
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/spf13/viper v1.7.1
|
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/valyala/fastjson v1.5.1
|
||||||
github.com/wcharczuk/go-chart/v2 v2.1.0
|
github.com/wcharczuk/go-chart/v2 v2.1.0
|
||||||
github.com/webview/webview v0.0.0-20210216142346-e0bfdf0e5d90
|
github.com/webview/webview v0.0.0-20210216142346-e0bfdf0e5d90
|
||||||
|
@ -93,7 +94,7 @@ require (
|
||||||
github.com/magiconair/properties v1.8.4 // indirect
|
github.com/magiconair/properties v1.8.4 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // 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/mattn/go-sqlite3 v1.14.13 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||||
|
|
20
go.sum
20
go.sum
|
@ -81,7 +81,6 @@ github.com/c9s/requestgen v1.3.0/go.mod h1:5n9FU3hr5307IiXAmbMiZbHYaPiys1u9jCWYe
|
||||||
github.com/c9s/rockhopper v1.2.2-0.20220617053729-ffdc87df194b h1:wT8c03PHLv7+nZUIGqxAzRvIfYHNxMCNVWwvdGkOXTs=
|
github.com/c9s/rockhopper v1.2.2-0.20220617053729-ffdc87df194b h1:wT8c03PHLv7+nZUIGqxAzRvIfYHNxMCNVWwvdGkOXTs=
|
||||||
github.com/c9s/rockhopper v1.2.2-0.20220617053729-ffdc87df194b/go.mod h1:EKObf66Cp7erWxym2de+07qNN5T1N9PXxHdh97N44EQ=
|
github.com/c9s/rockhopper v1.2.2-0.20220617053729-ffdc87df194b/go.mod h1:EKObf66Cp7erWxym2de+07qNN5T1N9PXxHdh97N44EQ=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||||
|
@ -149,7 +148,6 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
|
||||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
|
||||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
@ -351,6 +349,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.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
github.com/jackc/puddle v1.1.1/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/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 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4=
|
||||||
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag=
|
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=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
@ -439,8 +439,9 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
|
||||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
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.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 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
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=
|
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||||
|
@ -502,6 +503,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.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
@ -598,6 +600,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
|
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
|
||||||
|
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.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.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
@ -605,15 +609,16 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
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.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 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto=
|
github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto=
|
||||||
github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ=
|
github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
github.com/ugorji/go v1.2.3 h1:WbFSXLxDFKVN69Sk8t+XHGzVCD7R8UoAATR8NqZgTbk=
|
|
||||||
github.com/ugorji/go v1.2.3/go.mod h1:5l8GZ8hZvmL4uMdy+mhCO1LjswGRYco9Q3HfuisB21A=
|
github.com/ugorji/go v1.2.3/go.mod h1:5l8GZ8hZvmL4uMdy+mhCO1LjswGRYco9Q3HfuisB21A=
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/ugorji/go/codec v1.2.3 h1:/mVYEV+Jo3IZKeA5gBngN0AvNnQltEDkR+eQikkWQu0=
|
github.com/ugorji/go/codec v1.2.3 h1:/mVYEV+Jo3IZKeA5gBngN0AvNnQltEDkR+eQikkWQu0=
|
||||||
|
@ -633,7 +638,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
|
||||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||||
|
@ -766,8 +770,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0=
|
golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0=
|
||||||
golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
@ -846,7 +848,6 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU=
|
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU=
|
||||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -919,7 +920,6 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
|
||||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
|
||||||
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
|
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
|
||||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|
|
@ -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 {
|
func getStrategySignatures(exchangeStrategies map[string]SingleExchangeStrategy) []string {
|
||||||
var strategies []string
|
var strategies []string
|
||||||
for signature := range exchangeStrategies {
|
for signature := range exchangeStrategies {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package bbgo
|
package bbgo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/util"
|
"github.com/c9s/bbgo/pkg/util"
|
||||||
|
@ -20,9 +22,19 @@ func NotifyTo(channel string, obj interface{}, args ...interface{}) {
|
||||||
Notification.NotifyTo(channel, obj, args...)
|
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 {
|
type Notifier interface {
|
||||||
NotifyTo(channel string, obj interface{}, args ...interface{})
|
NotifyTo(channel string, obj interface{}, args ...interface{})
|
||||||
Notify(obj interface{}, args ...interface{})
|
Notify(obj interface{}, args ...interface{})
|
||||||
|
SendPhotoTo(channel string, buffer *bytes.Buffer)
|
||||||
|
SendPhoto(buffer *bytes.Buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type NullNotifier struct{}
|
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) Notify(obj interface{}, args ...interface{}) {}
|
||||||
|
|
||||||
|
func (n *NullNotifier) SendPhoto(buffer *bytes.Buffer) {}
|
||||||
|
|
||||||
|
func (n *NullNotifier) SendPhotoTo(channel string, buffer *bytes.Buffer) {}
|
||||||
|
|
||||||
type Notifiability struct {
|
type Notifiability struct {
|
||||||
notifiers []Notifier
|
notifiers []Notifier
|
||||||
SessionChannelRouter *PatternChannelRouter `json:"-"`
|
SessionChannelRouter *PatternChannelRouter `json:"-"`
|
||||||
|
@ -83,3 +99,15 @@ func (m *Notifiability) NotifyTo(channel string, obj interface{}, args ...interf
|
||||||
n.NotifyTo(channel, obj, args...)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -117,6 +117,10 @@ func (e *GeneralOrderExecutor) SubmitOrders(ctx context.Context, submitOrders ..
|
||||||
err = fmt.Errorf("can not place orders: %w", err)
|
err = fmt.Errorf("can not place orders: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// FIXME: map by price and volume
|
||||||
|
for i := 0; i < len(createdOrders); i++ {
|
||||||
|
createdOrders[i].Tag = formattedOrders[i].Tag
|
||||||
|
}
|
||||||
|
|
||||||
e.orderStore.Add(createdOrders...)
|
e.orderStore.Add(createdOrders...)
|
||||||
e.activeMakerOrders.Add(createdOrders...)
|
e.activeMakerOrders.Add(createdOrders...)
|
||||||
|
|
|
@ -104,8 +104,9 @@ func (s *OrderStore) Update(o types.Order) bool {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
_, ok := s.orders[o.OrderID]
|
old, ok := s.orders[o.OrderID]
|
||||||
if ok {
|
if ok {
|
||||||
|
o.Tag = old.Tag
|
||||||
s.orders[o.OrderID] = o
|
s.orders[o.OrderID] = o
|
||||||
}
|
}
|
||||||
return ok
|
return ok
|
||||||
|
|
|
@ -34,6 +34,10 @@ func (inc *FisherTransform) Update(value float64) {
|
||||||
inc.prices.Update(value)
|
inc.prices.Update(value)
|
||||||
highest := inc.prices.Highest(inc.Window)
|
highest := inc.prices.Highest(inc.Window)
|
||||||
lowest := inc.prices.Lowest(inc.Window)
|
lowest := inc.prices.Lowest(inc.Window)
|
||||||
|
if highest == lowest {
|
||||||
|
inc.Values.Update(0)
|
||||||
|
return
|
||||||
|
}
|
||||||
x := 2*((value-lowest)/(highest-lowest)) - 1
|
x := 2*((value-lowest)/(highest-lowest)) - 1
|
||||||
if x == 1 {
|
if x == 1 {
|
||||||
x = 0.9999
|
x = 0.9999
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package slacknotifier
|
package slacknotifier
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"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) {
|
func (n *Notifier) NotifyTrade(trade *types.Trade) {
|
||||||
_, _, err := n.client.PostMessageContext(context.Background(), n.TradeChannel,
|
_, _, err := n.client.PostMessageContext(context.Background(), n.TradeChannel,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package telegramnotifier
|
package telegramnotifier
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"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) {
|
func (n *Notifier) AddChat(c *telebot.Chat) {
|
||||||
if n.Chats == nil {
|
if n.Chats == nil {
|
||||||
n.Chats = make(map[int64]*telebot.Chat)
|
n.Chats = make(map[int64]*telebot.Chat)
|
||||||
|
|
51
pkg/strategy/drift/driftma.go
Normal file
51
pkg/strategy/drift/driftma.go
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package drift
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/c9s/bbgo/pkg/indicator"
|
||||||
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DriftMA struct {
|
||||||
|
types.SeriesBase
|
||||||
|
ma1 types.UpdatableSeriesExtend
|
||||||
|
drift *indicator.Drift
|
||||||
|
ma2 types.UpdatableSeriesExtend
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DriftMA) Update(value float64) {
|
||||||
|
s.ma1.Update(value)
|
||||||
|
s.drift.Update(s.ma1.Last())
|
||||||
|
s.ma2.Update(s.drift.Last())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DriftMA) Last() float64 {
|
||||||
|
return s.ma2.Last()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DriftMA) Index(i int) float64 {
|
||||||
|
return s.ma2.Index(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DriftMA) Length() int {
|
||||||
|
return s.ma2.Length()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DriftMA) ZeroPoint() float64 {
|
||||||
|
return s.drift.ZeroPoint()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DriftMA) Clone() *DriftMA {
|
||||||
|
out := DriftMA{
|
||||||
|
ma1: types.Clone(s.ma1),
|
||||||
|
drift: s.drift.Clone(),
|
||||||
|
ma2: types.Clone(s.ma2),
|
||||||
|
}
|
||||||
|
out.SeriesBase.Series = &out
|
||||||
|
return &out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DriftMA) TestUpdate(v float64) *DriftMA {
|
||||||
|
out := s.Clone()
|
||||||
|
out.Update(v)
|
||||||
|
return out
|
||||||
|
}
|
210
pkg/strategy/drift/output.go
Normal file
210
pkg/strategy/drift/output.go
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
package drift
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/util"
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"github.com/jedib0t/go-pretty/v6/table"
|
||||||
|
"github.com/jedib0t/go-pretty/v6/text"
|
||||||
|
)
|
||||||
|
|
||||||
|
type jsonStruct struct {
|
||||||
|
key string
|
||||||
|
json string
|
||||||
|
tp string
|
||||||
|
value interface{}
|
||||||
|
}
|
||||||
|
type jsonArr []jsonStruct
|
||||||
|
|
||||||
|
func (a jsonArr) Len() int { return len(a) }
|
||||||
|
func (a jsonArr) Less(i, j int) bool { return a[i].key < a[j].key }
|
||||||
|
func (a jsonArr) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
|
|
||||||
|
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 field.CanConvert(reflect.TypeOf(int(0))) {
|
||||||
|
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) {
|
||||||
|
//b, _ := json.MarshalIndent(s.ExitMethods, " ", " ")
|
||||||
|
|
||||||
|
t := table.NewWriter()
|
||||||
|
style := table.Style{
|
||||||
|
Name: "StyleRounded",
|
||||||
|
Box: table.StyleBoxRounded,
|
||||||
|
Color: table.ColorOptionsDefault,
|
||||||
|
Format: table.FormatOptionsDefault,
|
||||||
|
HTML: table.DefaultHTMLOptions,
|
||||||
|
Options: table.OptionsDefault,
|
||||||
|
Title: table.TitleOptionsDefault,
|
||||||
|
}
|
||||||
|
var hiyellow func(io.Writer, string, ...interface{})
|
||||||
|
if len(withColor) > 0 && withColor[0] {
|
||||||
|
if pretty {
|
||||||
|
style.Color = table.ColorOptionsYellowWhiteOnBlack
|
||||||
|
style.Color.Row = text.Colors{text.FgHiYellow, text.BgHiBlack}
|
||||||
|
style.Color.RowAlternate = text.Colors{text.FgYellow, text.BgBlack}
|
||||||
|
}
|
||||||
|
hiyellow = color.New(color.FgHiYellow).FprintfFunc()
|
||||||
|
} else {
|
||||||
|
hiyellow = func(a io.Writer, format string, args ...interface{}) {
|
||||||
|
fmt.Fprintf(a, format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pretty {
|
||||||
|
t.SetOutputMirror(f)
|
||||||
|
t.SetStyle(style)
|
||||||
|
t.AppendHeader(table.Row{"json", "struct field name", "type", "value"})
|
||||||
|
}
|
||||||
|
hiyellow(f, "------ %s Settings ------\n", s.InstanceID())
|
||||||
|
|
||||||
|
embeddedWhiteSet := map[string]struct{}{"Window": {}, "Interval": {}, "Symbol": {}}
|
||||||
|
redundantSet := map[string]struct{}{}
|
||||||
|
var rows []table.Row
|
||||||
|
val := reflect.ValueOf(*s)
|
||||||
|
var values jsonArr
|
||||||
|
for i := 0; i < val.Type().NumField(); i++ {
|
||||||
|
t := val.Type().Field(i)
|
||||||
|
if !t.IsExported() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fieldName := t.Name
|
||||||
|
switch jsonTag := t.Tag.Get("json"); jsonTag {
|
||||||
|
case "-":
|
||||||
|
case "":
|
||||||
|
if t.Anonymous {
|
||||||
|
var target reflect.Type
|
||||||
|
if t.Type.Kind() == util.Pointer {
|
||||||
|
target = t.Type.Elem()
|
||||||
|
} else {
|
||||||
|
target = t.Type
|
||||||
|
}
|
||||||
|
for j := 0; j < target.NumField(); j++ {
|
||||||
|
tt := target.Field(j)
|
||||||
|
if !tt.IsExported() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fieldName := tt.Name
|
||||||
|
if _, ok := embeddedWhiteSet[fieldName]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if jtag := tt.Tag.Get("json"); jtag != "" && jtag != "-" {
|
||||||
|
name := strings.Split(jtag, ",")[0]
|
||||||
|
if _, ok := redundantSet[name]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
redundantSet[name] = struct{}{}
|
||||||
|
var value interface{}
|
||||||
|
if t.Type.Kind() == util.Pointer {
|
||||||
|
value = val.Field(i).Elem().Field(j).Interface()
|
||||||
|
} else {
|
||||||
|
value = val.Field(i).Field(j).Interface()
|
||||||
|
}
|
||||||
|
values = append(values, jsonStruct{key: fieldName, json: name, tp: tt.Type.String(), value: value})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
name := strings.Split(jsonTag, ",")[0]
|
||||||
|
if _, ok := redundantSet[name]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
redundantSet[name] = struct{}{}
|
||||||
|
values = append(values, jsonStruct{key: fieldName, json: name, tp: t.Type.String(), value: val.Field(i).Interface()})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Sort(values)
|
||||||
|
for _, value := range values {
|
||||||
|
if pretty {
|
||||||
|
rows = append(rows, table.Row{value.json, value.key, value.tp, value.value})
|
||||||
|
} else {
|
||||||
|
hiyellow(f, "%s: %v\n", value.json, value.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pretty {
|
||||||
|
t.AppendRows(rows)
|
||||||
|
t.Render()
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1192,16 +1192,35 @@ func NewCanvas(title string, intervals ...Interval) *Canvas {
|
||||||
return out
|
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
|
var timeline []time.Time
|
||||||
e := endTime.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-- {
|
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)
|
timeline = append(timeline, shiftedT)
|
||||||
}
|
}
|
||||||
canvas.Series = append(canvas.Series, chart.TimeSeries{
|
canvas.Series = append(canvas.Series, chart.TimeSeries{
|
||||||
Name: tag,
|
Name: tag,
|
||||||
YValues: Reverse(a, length),
|
YValues: expand(Reverse(a, length), length, oldest),
|
||||||
XValues: timeline,
|
XValues: timeline,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1211,10 +1230,14 @@ func (canvas *Canvas) PlotRaw(tag string, a Series, length int) {
|
||||||
for i := 0; i < length; i++ {
|
for i := 0; i < length; i++ {
|
||||||
x = append(x, float64(i))
|
x = append(x, float64(i))
|
||||||
}
|
}
|
||||||
|
if a.Length() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oldest := a.Index(a.Length() - 1)
|
||||||
canvas.Series = append(canvas.Series, chart.ContinuousSeries{
|
canvas.Series = append(canvas.Series, chart.ContinuousSeries{
|
||||||
Name: tag,
|
Name: tag,
|
||||||
XValues: x,
|
XValues: x,
|
||||||
YValues: Reverse(a, length),
|
YValues: expand(Reverse(a, length), length, oldest),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -10,13 +12,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type IntervalProfitCollector struct {
|
type IntervalProfitCollector struct {
|
||||||
Interval Interval `json:"interval"`
|
Interval Interval `json:"interval"`
|
||||||
Profits *Float64Slice `json:"profits"`
|
Profits *Float64Slice `json:"profits"`
|
||||||
tmpTime time.Time `json:"tmpTime"`
|
Timestamp *Float64Slice `json:"timestamp"`
|
||||||
|
tmpTime time.Time `json:"tmpTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIntervalProfitCollector(i Interval, startTime time.Time) *IntervalProfitCollector {
|
func NewIntervalProfitCollector(i Interval, startTime time.Time) *IntervalProfitCollector {
|
||||||
return &IntervalProfitCollector{Interval: i, tmpTime: startTime, Profits: &Float64Slice{1.}}
|
return &IntervalProfitCollector{Interval: i, tmpTime: startTime, Profits: &Float64Slice{1.}, Timestamp: &Float64Slice{float64(startTime.Unix())}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the collector by every traded profit
|
// Update the collector by every traded profit
|
||||||
|
@ -31,6 +34,7 @@ func (s *IntervalProfitCollector) Update(profit *Profit) {
|
||||||
for {
|
for {
|
||||||
s.Profits.Update(1.)
|
s.Profits.Update(1.)
|
||||||
s.tmpTime = s.tmpTime.Add(duration)
|
s.tmpTime = s.tmpTime.Add(duration)
|
||||||
|
s.Timestamp.Update(float64(s.tmpTime.Unix()))
|
||||||
if profit.TradedAt.Before(s.tmpTime.Add(duration)) {
|
if profit.TradedAt.Before(s.tmpTime.Add(duration)) {
|
||||||
(*s.Profits)[len(*s.Profits)-1] *= 1. + profit.NetProfitMargin.Float64()
|
(*s.Profits)[len(*s.Profits)-1] *= 1. + profit.NetProfitMargin.Float64()
|
||||||
break
|
break
|
||||||
|
@ -40,6 +44,48 @@ func (s *IntervalProfitCollector) Update(profit *Profit) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProfitReport struct {
|
||||||
|
StartTime time.Time `json:"startTime"`
|
||||||
|
Profit float64 `json:"profit"`
|
||||||
|
Interval Interval `json:"interval"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ProfitReport) String() string {
|
||||||
|
b, err := json.MarshalIndent(s, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all none-profitable intervals
|
||||||
|
func (s *IntervalProfitCollector) GetNonProfitableIntervals() (result []ProfitReport) {
|
||||||
|
if s.Profits == nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
l := s.Profits.Length()
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
if s.Profits.Index(i) <= 1. {
|
||||||
|
result = append(result, ProfitReport{StartTime: time.Unix(int64(s.Timestamp.Index(i)), 0), Profit: s.Profits.Index(i), Interval: s.Interval})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all profitable intervals
|
||||||
|
func (s *IntervalProfitCollector) GetProfitableIntervals() (result []ProfitReport) {
|
||||||
|
if s.Profits == nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
l := s.Profits.Length()
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
if s.Profits.Index(i) > 1. {
|
||||||
|
result = append(result, ProfitReport{StartTime: time.Unix(int64(s.Timestamp.Index(i)), 0), Profit: s.Profits.Index(i), Interval: s.Interval})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// Get number of profitable traded intervals
|
// Get number of profitable traded intervals
|
||||||
func (s *IntervalProfitCollector) GetNumOfProfitableIntervals() (profit int) {
|
func (s *IntervalProfitCollector) GetNumOfProfitableIntervals() (profit int) {
|
||||||
if s.Profits == nil {
|
if s.Profits == nil {
|
||||||
|
@ -226,6 +272,8 @@ func (s *TradeStats) BriefString() string {
|
||||||
GrossLoss: s.GrossLoss,
|
GrossLoss: s.GrossLoss,
|
||||||
LargestProfitTrade: s.LargestProfitTrade,
|
LargestProfitTrade: s.LargestProfitTrade,
|
||||||
LargestLossTrade: s.LargestLossTrade,
|
LargestLossTrade: s.LargestLossTrade,
|
||||||
|
AverageProfitTrade: s.AverageProfitTrade,
|
||||||
|
AverageLossTrade: s.AverageLossTrade,
|
||||||
ProfitFactor: s.ProfitFactor,
|
ProfitFactor: s.ProfitFactor,
|
||||||
TotalNetProfit: s.TotalNetProfit,
|
TotalNetProfit: s.TotalNetProfit,
|
||||||
IntervalProfits: s.IntervalProfits,
|
IntervalProfits: s.IntervalProfits,
|
||||||
|
|
8
pkg/util/pointer.go
Normal file
8
pkg/util/pointer.go
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
//go:build !go1.18
|
||||||
|
// +build !go1.18
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
const Pointer = reflect.Ptr
|
8
pkg/util/pointer_18.go
Normal file
8
pkg/util/pointer_18.go
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
//go:build go1.18
|
||||||
|
// +build go1.18
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
const Pointer = reflect.Pointer
|
Loading…
Reference in New Issue
Block a user