mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
feature: export drift1m, remove take profit, add profit report for listing pnl by date
This commit is contained in:
parent
da28750313
commit
c1d9df8cdb
|
@ -31,25 +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
|
trailingStopLossType: kline
|
||||||
# stddev on high/low-source
|
# stddev on high/low-source
|
||||||
hlVarianceMultiplier: 0.23
|
hlVarianceMultiplier: 0.23
|
||||||
hlRangeWindow: 5
|
hlRangeWindow: 5
|
||||||
|
window1m: 24
|
||||||
|
smootherWindow1m: 24
|
||||||
|
fisherTransformWindow1m: 162
|
||||||
smootherWindow: 1
|
smootherWindow: 1
|
||||||
fisherTransformWindow: 9
|
fisherTransformWindow: 9
|
||||||
atrWindow: 14
|
atrWindow: 14
|
||||||
# orders not been traded will be canceled after `pendingMinutes` minutes
|
# orders not been traded will be canceled after `pendingMinutes` minutes
|
||||||
pendingMinutes: 4
|
pendingMinutes: 3
|
||||||
noRebalance: true
|
noRebalance: true
|
||||||
trendWindow: 12
|
trendWindow: 12
|
||||||
rebalanceFilter: 1.5
|
rebalanceFilter: 1.5
|
||||||
|
|
||||||
trailingActivationRatio: [0.008, 0.015]
|
trailingActivationRatio: [0.004]
|
||||||
trailingCallbackRate: [0.002, 0.001]
|
trailingCallbackRate: [0.001]
|
||||||
|
|
||||||
generateGraph: true
|
generateGraph: true
|
||||||
graphPNLDeductFee: true
|
graphPNLDeductFee: true
|
||||||
|
@ -88,7 +88,7 @@ sync:
|
||||||
|
|
||||||
backtest:
|
backtest:
|
||||||
startTime: "2022-01-01"
|
startTime: "2022-01-01"
|
||||||
endTime: "2022-07-30"
|
endTime: "2022-08-30"
|
||||||
symbols:
|
symbols:
|
||||||
- ETHBUSD
|
- ETHBUSD
|
||||||
sessions: [binance]
|
sessions: [binance]
|
||||||
|
|
|
@ -38,6 +38,9 @@ exchangeStrategies:
|
||||||
hlRangeWindow: 5
|
hlRangeWindow: 5
|
||||||
smootherWindow: 1
|
smootherWindow: 1
|
||||||
fisherTransformWindow: 9
|
fisherTransformWindow: 9
|
||||||
|
window1m: 28
|
||||||
|
smootherWindow1m: 14
|
||||||
|
fisherTransformWindow1m: 162
|
||||||
# the init value of takeProfitFactor Series, the coefficient of ATR as TP
|
# the init value of takeProfitFactor Series, the coefficient of ATR as TP
|
||||||
takeProfitFactor: 4
|
takeProfitFactor: 4
|
||||||
profitFactorWindow: 5
|
profitFactorWindow: 5
|
||||||
|
@ -51,11 +54,11 @@ exchangeStrategies:
|
||||||
# ActivationRatio should be increasing order
|
# ActivationRatio should be increasing order
|
||||||
# when farest price from entry goes over that ratio, start using the callback ratio accordingly to do trailingstop
|
# when farest price from entry goes over that ratio, start using the callback ratio accordingly to do trailingstop
|
||||||
#trailingActivationRatio: [0.007, 0.011, 0.02, 0.05]
|
#trailingActivationRatio: [0.007, 0.011, 0.02, 0.05]
|
||||||
trailingActivationRatio: [0.001, 0.002, 0.004]
|
trailingActivationRatio: [0.002, 0.02, 0.04]
|
||||||
#trailingActivationRatio: []
|
#trailingActivationRatio: []
|
||||||
#trailingCallbackRate: []
|
#trailingCallbackRate: []
|
||||||
#trailingCallbackRate: [0.002, 0.001, 0.002, 0.001]
|
#trailingCallbackRate: [0.002, 0.001, 0.002, 0.001]
|
||||||
trailingCallbackRate: [0.0005, 0.0008, 0.002]
|
trailingCallbackRate: [0.0005, 0.001, 0.003]
|
||||||
|
|
||||||
generateGraph: true
|
generateGraph: true
|
||||||
graphPNLDeductFee: false
|
graphPNLDeductFee: false
|
||||||
|
@ -128,5 +131,5 @@ backtest:
|
||||||
makerFeeRate: 0.000
|
makerFeeRate: 0.000
|
||||||
#takerFeeRate: 0.000
|
#takerFeeRate: 0.000
|
||||||
balances:
|
balances:
|
||||||
BTC: 1
|
BTC: 0
|
||||||
USDT: 5000
|
USDT: 21
|
||||||
|
|
2
go.mod
2
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
|
||||||
|
@ -83,7 +84,6 @@ require (
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap 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/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
|
||||||
github.com/json-iterator/go v1.1.11 // indirect
|
github.com/json-iterator/go v1.1.11 // indirect
|
||||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||||
|
|
11
go.sum
11
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=
|
||||||
|
@ -441,7 +439,6 @@ 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 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
@ -603,6 +600,7 @@ 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/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=
|
||||||
|
@ -611,7 +609,6 @@ 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.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM=
|
github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM=
|
||||||
|
@ -622,7 +619,6 @@ 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=
|
||||||
|
@ -642,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=
|
||||||
|
@ -775,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=
|
||||||
|
@ -855,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=
|
||||||
|
@ -928,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=
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -43,6 +43,7 @@ func (s *Strategy) ParamDump(f io.Writer, seriesLength ...int) {
|
||||||
}
|
}
|
||||||
fieldName := t.Name
|
fieldName := t.Name
|
||||||
typeName := field.Type().String()
|
typeName := field.Type().String()
|
||||||
|
log.Infof("fieldName %s typeName %s", fieldName, typeName)
|
||||||
value := reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem()
|
value := reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem()
|
||||||
isSeries := true
|
isSeries := true
|
||||||
lastFunc := value.MethodByName("Last")
|
lastFunc := value.MethodByName("Last")
|
||||||
|
@ -82,7 +83,7 @@ func (s *Strategy) ParamDump(f io.Writer, seriesLength ...int) {
|
||||||
fmt.Fprintf(f, "%s: %v", fieldName, field.Interface())
|
fmt.Fprintf(f, "%s: %v", fieldName, field.Interface())
|
||||||
} else if field.Type().Kind() == reflect.Map {
|
} else if field.Type().Kind() == reflect.Map {
|
||||||
fmt.Fprintf(f, "%s: {", fieldName)
|
fmt.Fprintf(f, "%s: {", fieldName)
|
||||||
iter := field.MapRange()
|
iter := value.MapRange()
|
||||||
for iter.Next() {
|
for iter.Next() {
|
||||||
k := iter.Key().Interface()
|
k := iter.Key().Interface()
|
||||||
v := iter.Value().Interface()
|
v := iter.Value().Interface()
|
||||||
|
@ -203,10 +204,7 @@ func (s *Strategy) Print(f io.Writer, pretty bool, withColor ...bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pretty {
|
if pretty {
|
||||||
rows = append(rows, table.Row{"takeProfitFactor(last)", "takeProfitFactor", "float64", s.takeProfitFactor.Last()})
|
|
||||||
t.AppendRows(rows)
|
t.AppendRows(rows)
|
||||||
t.Render()
|
t.Render()
|
||||||
} else {
|
|
||||||
hiyellow(f, "takeProfitFactor(last): %f\n", s.takeProfitFactor.Last())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,12 +73,7 @@ type Strategy struct {
|
||||||
|
|
||||||
beta float64
|
beta float64
|
||||||
|
|
||||||
// This stores the maximum TP coefficient of ATR multiplier of each entry point
|
|
||||||
takeProfitFactor types.UpdatableSeriesExtend
|
|
||||||
|
|
||||||
Source string `json:"source,omitempty"`
|
Source string `json:"source,omitempty"`
|
||||||
TakeProfitFactor float64 `json:"takeProfitFactor"`
|
|
||||||
ProfitFactorWindow int `json:"profitFactorWindow"`
|
|
||||||
StopLoss fixedpoint.Value `json:"stoploss"`
|
StopLoss fixedpoint.Value `json:"stoploss"`
|
||||||
CanvasPath string `json:"canvasPath"`
|
CanvasPath string `json:"canvasPath"`
|
||||||
PredictOffset int `json:"predictOffset"`
|
PredictOffset int `json:"predictOffset"`
|
||||||
|
@ -86,6 +81,9 @@ type Strategy struct {
|
||||||
NoTrailingStopLoss bool `json:"noTrailingStopLoss"`
|
NoTrailingStopLoss bool `json:"noTrailingStopLoss"`
|
||||||
TrailingStopLossType string `json:"trailingStopLossType"` // trailing stop sources. Possible options are `kline` for 1m kline and `realtime` from order updates
|
TrailingStopLossType string `json:"trailingStopLossType"` // trailing stop sources. Possible options are `kline` for 1m kline and `realtime` from order updates
|
||||||
HLRangeWindow int `json:"hlRangeWindow"`
|
HLRangeWindow int `json:"hlRangeWindow"`
|
||||||
|
Window1m int `json:"window1m"`
|
||||||
|
SmootherWindow1m int `json:"smootherWindow1m"`
|
||||||
|
FisherTransformWindow1m int `json:"fisherTransformWindow1m"`
|
||||||
SmootherWindow int `json:"smootherWindow"`
|
SmootherWindow int `json:"smootherWindow"`
|
||||||
FisherTransformWindow int `json:"fisherTransformWindow"`
|
FisherTransformWindow int `json:"fisherTransformWindow"`
|
||||||
ATRWindow int `json:"atrWindow"`
|
ATRWindow int `json:"atrWindow"`
|
||||||
|
@ -225,24 +223,20 @@ func (s *Strategy) initIndicators(priceLines *types.Queue) error {
|
||||||
s.drift.SeriesBase.Series = s.drift
|
s.drift.SeriesBase.Series = s.drift
|
||||||
s.drift1m = &DriftMA{
|
s.drift1m = &DriftMA{
|
||||||
drift: &indicator.Drift{
|
drift: &indicator.Drift{
|
||||||
MA: &indicator.SMA{IntervalWindow: types.IntervalWindow{Interval: types.Interval1m, Window: 2}},
|
MA: &indicator.SMA{IntervalWindow: types.IntervalWindow{Interval: types.Interval1m, Window: s.Window1m}},
|
||||||
IntervalWindow: types.IntervalWindow{Interval: types.Interval1m, Window: 2},
|
IntervalWindow: types.IntervalWindow{Interval: types.Interval1m, Window: s.Window1m},
|
||||||
},
|
},
|
||||||
ma1: &indicator.EWMA{
|
ma1: &indicator.EWMA{
|
||||||
IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: 24},
|
IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.SmootherWindow1m},
|
||||||
},
|
},
|
||||||
ma2: &indicator.FisherTransform{
|
ma2: &indicator.FisherTransform{
|
||||||
IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.FisherTransformWindow * 15},
|
IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.FisherTransformWindow1m},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
s.drift1m.SeriesBase.Series = s.drift1m
|
s.drift1m.SeriesBase.Series = s.drift1m
|
||||||
s.atr = &indicator.ATR{IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.ATRWindow}}
|
s.atr = &indicator.ATR{IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.ATRWindow}}
|
||||||
s.takeProfitFactor = &indicator.SMA{IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.ProfitFactorWindow}}
|
|
||||||
s.trendLine = &indicator.EWMA{IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.TrendWindow}}
|
s.trendLine = &indicator.EWMA{IntervalWindow: types.IntervalWindow{Interval: s.Interval, Window: s.TrendWindow}}
|
||||||
|
|
||||||
for i := 0; i <= s.ProfitFactorWindow; i++ {
|
|
||||||
s.takeProfitFactor.Update(s.TakeProfitFactor)
|
|
||||||
}
|
|
||||||
store, _ := s.Session.MarketDataStore(s.Symbol)
|
store, _ := s.Session.MarketDataStore(s.Symbol)
|
||||||
klines, ok := store.KLinesOfInterval(s.Interval)
|
klines, ok := store.KLinesOfInterval(s.Interval)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -271,6 +265,9 @@ func (s *Strategy) initIndicators(priceLines *types.Queue) error {
|
||||||
for _, kline := range *klines {
|
for _, kline := range *klines {
|
||||||
source := s.getSource(&kline).Float64()
|
source := s.getSource(&kline).Float64()
|
||||||
s.drift1m.Update(source)
|
s.drift1m.Update(source)
|
||||||
|
if s.drift1m.Last() != s.drift1m.Last() {
|
||||||
|
panic(fmt.Sprintf("%f %v %f %f", source, s.drift1m.drift.Values.Index(1), s.drift1m.ma2.Last(), s.drift1m.drift.LastValue))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if s.kline1m != nil && klines != nil {
|
if s.kline1m != nil && klines != nil {
|
||||||
s.kline1m.Set(&(*klines)[len(*klines)-1])
|
s.kline1m.Set(&(*klines)[len(*klines)-1])
|
||||||
|
@ -278,7 +275,7 @@ func (s *Strategy) initIndicators(priceLines *types.Queue) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Strategy) smartCancel(ctx context.Context, pricef, atr, takeProfitFactor float64) (int, error) {
|
func (s *Strategy) smartCancel(ctx context.Context, pricef, atr float64) (int, error) {
|
||||||
nonTraded := s.GeneralOrderExecutor.ActiveMakerOrders().Orders()
|
nonTraded := s.GeneralOrderExecutor.ActiveMakerOrders().Orders()
|
||||||
if len(nonTraded) > 0 {
|
if len(nonTraded) > 0 {
|
||||||
if len(nonTraded) > 1 {
|
if len(nonTraded) > 1 {
|
||||||
|
@ -364,7 +361,9 @@ func (s *Strategy) initTickerFunctions(ctx context.Context) {
|
||||||
bestAsk := ticker.Sell
|
bestAsk := ticker.Sell
|
||||||
|
|
||||||
var pricef, atr float64
|
var pricef, atr float64
|
||||||
if util.TryLock(&s.lock) {
|
if !util.TryLock(&s.lock) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if !bestAsk.IsZero() && !bestBid.IsZero() {
|
if !bestAsk.IsZero() && !bestBid.IsZero() {
|
||||||
s.midPrice = bestAsk.Add(bestBid).Div(Two)
|
s.midPrice = bestAsk.Add(bestBid).Div(Two)
|
||||||
} else if !bestAsk.IsZero() {
|
} else if !bestAsk.IsZero() {
|
||||||
|
@ -373,30 +372,12 @@ func (s *Strategy) initTickerFunctions(ctx context.Context) {
|
||||||
s.midPrice = bestBid
|
s.midPrice = bestBid
|
||||||
}
|
}
|
||||||
pricef = s.midPrice.Float64()
|
pricef = s.midPrice.Float64()
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
s.lock.Unlock()
|
s.lock.Unlock()
|
||||||
// for trailing stoploss during the realtime
|
|
||||||
if s.NoTrailingStopLoss || s.TrailingStopLossType == "kline" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stoploss := s.StopLoss.Float64()
|
if !util.TryLock(&s.positionLock) {
|
||||||
atr = s.atr.Last()
|
|
||||||
takeProfitFactor := s.takeProfitFactor.Predict(2)
|
|
||||||
numPending := 0
|
|
||||||
var err error
|
|
||||||
if numPending, err = s.smartCancel(ctx, pricef, atr, takeProfitFactor); err != nil {
|
|
||||||
log.WithError(err).Errorf("cannot cancel orders")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if numPending > 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
s.positionLock.Lock()
|
|
||||||
|
|
||||||
if s.highestPrice > 0 && s.highestPrice < pricef {
|
if s.highestPrice > 0 && s.highestPrice < pricef {
|
||||||
s.highestPrice = pricef
|
s.highestPrice = pricef
|
||||||
|
@ -404,18 +385,29 @@ func (s *Strategy) initTickerFunctions(ctx context.Context) {
|
||||||
if s.lowestPrice > 0 && s.lowestPrice > pricef {
|
if s.lowestPrice > 0 && s.lowestPrice > pricef {
|
||||||
s.lowestPrice = pricef
|
s.lowestPrice = pricef
|
||||||
}
|
}
|
||||||
|
// for trailing stoploss during the realtime
|
||||||
|
if s.NoTrailingStopLoss || s.TrailingStopLossType == "kline" {
|
||||||
|
s.positionLock.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
exitShortCondition := s.sellPrice > 0 && (s.sellPrice*(1.+stoploss) <= pricef || s.sellPrice-atr*takeProfitFactor >= pricef ||
|
stoploss := s.StopLoss.Float64()
|
||||||
|
atr = s.atr.Last()
|
||||||
|
numPending := 0
|
||||||
|
var err error
|
||||||
|
if numPending, err = s.smartCancel(ctx, pricef, atr); err != nil {
|
||||||
|
log.WithError(err).Errorf("cannot cancel orders")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if numPending > 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
exitShortCondition := s.sellPrice > 0 && (s.sellPrice*(1.+stoploss) <= pricef ||
|
||||||
s.trailingCheck(pricef, "short"))
|
s.trailingCheck(pricef, "short"))
|
||||||
exitLongCondition := s.buyPrice > 0 && (s.buyPrice*(1.-stoploss) >= pricef || s.buyPrice+atr*takeProfitFactor <= 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 exitLongCondition && s.highestPrice > s.buyPrice {
|
|
||||||
s.takeProfitFactor.Update((s.highestPrice - s.buyPrice) / atr * 1.5)
|
|
||||||
}
|
|
||||||
if exitShortCondition && s.sellPrice > s.lowestPrice {
|
|
||||||
s.takeProfitFactor.Update((s.sellPrice - s.lowestPrice) / atr * 1.5)
|
|
||||||
}
|
|
||||||
log.Infof("Close position by orderbook changes")
|
log.Infof("Close position by orderbook changes")
|
||||||
s.positionLock.Unlock()
|
s.positionLock.Unlock()
|
||||||
_ = s.ClosePosition(ctx, fixedpoint.One)
|
_ = s.ClosePosition(ctx, fixedpoint.One)
|
||||||
|
@ -453,12 +445,20 @@ func (s *Strategy) DrawIndicators(time types.Time, priceLine types.SeriesExtend,
|
||||||
highestPrice := priceLine.Minus(mean).Abs().Highest(Length)
|
highestPrice := priceLine.Minus(mean).Abs().Highest(Length)
|
||||||
highestDrift := s.drift.Abs().Highest(Length)
|
highestDrift := s.drift.Abs().Highest(Length)
|
||||||
hi := s.drift.drift.Abs().Highest(Length)
|
hi := s.drift.drift.Abs().Highest(Length)
|
||||||
|
h1m := s.drift1m.Abs().Highest(Length * s.Interval.Minutes())
|
||||||
ratio := highestPrice / highestDrift
|
ratio := highestPrice / highestDrift
|
||||||
|
for i := 0; i < s.drift1m.Length(); i++ {
|
||||||
|
if s.drift1m.Index(i) != s.drift1m.Index(i) {
|
||||||
|
log.Infof("%d, %f", i, s.drift1m.Index(i-1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Infof("%d, %v", s.drift1m.Length(), s.drift1m.Array(10))
|
||||||
canvas.Plot("upband", s.ma.Add(s.stdevHigh), time, Length)
|
canvas.Plot("upband", s.ma.Add(s.stdevHigh), time, Length)
|
||||||
canvas.Plot("ma", s.ma, time, Length)
|
canvas.Plot("ma", s.ma, time, Length)
|
||||||
canvas.Plot("downband", s.ma.Minus(s.stdevLow), time, Length)
|
canvas.Plot("downband", s.ma.Minus(s.stdevLow), time, Length)
|
||||||
canvas.Plot("drift", s.drift.Mul(ratio).Add(mean), time, Length)
|
canvas.Plot("drift", s.drift.Mul(ratio).Add(mean), time, Length)
|
||||||
canvas.Plot("driftOrig", s.drift.drift.Mul(highestPrice/hi).Add(mean), time, Length)
|
canvas.Plot("driftOrig", s.drift.drift.Mul(highestPrice/hi).Add(mean), time, Length)
|
||||||
|
canvas.Plot("drift1m", s.drift1m.Mul(highestPrice/h1m).Add(mean), time, Length*s.Interval.Minutes(), types.Interval1m)
|
||||||
canvas.Plot("zero", types.NumberSeries(mean), time, Length)
|
canvas.Plot("zero", types.NumberSeries(mean), time, Length)
|
||||||
canvas.Plot("price", priceLine, time, Length)
|
canvas.Plot("price", priceLine, time, Length)
|
||||||
canvas.Plot("zeroPoint", zeroPoints, time, Length)
|
canvas.Plot("zeroPoint", zeroPoints, time, Length)
|
||||||
|
@ -821,10 +821,9 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
price := s.getLastPrice()
|
price := s.getLastPrice()
|
||||||
pricef := price.Float64()
|
pricef := price.Float64()
|
||||||
|
|
||||||
takeProfitFactor := s.takeProfitFactor.Predict(2)
|
|
||||||
var err error
|
var err error
|
||||||
numPending := 0
|
numPending := 0
|
||||||
if numPending, err = s.smartCancel(ctx, pricef, atr, takeProfitFactor); err != nil {
|
if numPending, err = s.smartCancel(ctx, pricef, atr); err != nil {
|
||||||
log.WithError(err).Errorf("cannot cancel orders")
|
log.WithError(err).Errorf("cannot cancel orders")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -842,17 +841,11 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
if s.highestPrice > 0 && highf > s.highestPrice {
|
if s.highestPrice > 0 && highf > s.highestPrice {
|
||||||
s.highestPrice = highf
|
s.highestPrice = highf
|
||||||
}
|
}
|
||||||
exitShortCondition := s.sellPrice > 0 && (s.sellPrice*(1.+stoploss) <= highf || s.sellPrice-atr*takeProfitFactor >= lowf ||
|
exitShortCondition := s.sellPrice > 0 && (s.sellPrice*(1.+stoploss) <= highf ||
|
||||||
s.trailingCheck(highf, "short"))
|
s.trailingCheck(highf, "short") || s.drift1m.Last() > 0)
|
||||||
exitLongCondition := s.buyPrice > 0 && (s.buyPrice*(1.-stoploss) >= lowf || s.buyPrice+atr*takeProfitFactor <= highf ||
|
exitLongCondition := s.buyPrice > 0 && (s.buyPrice*(1.-stoploss) >= lowf ||
|
||||||
s.trailingCheck(lowf, "long"))
|
s.trailingCheck(lowf, "long") || s.drift1m.Last() < 0)
|
||||||
if exitShortCondition || exitLongCondition {
|
if exitShortCondition || exitLongCondition {
|
||||||
if exitLongCondition && s.highestPrice > s.buyPrice {
|
|
||||||
s.takeProfitFactor.Update((s.highestPrice - s.buyPrice) / atr * 1.5)
|
|
||||||
}
|
|
||||||
if exitShortCondition && s.sellPrice > s.lowestPrice {
|
|
||||||
s.takeProfitFactor.Update((s.sellPrice - s.lowestPrice) / atr * 1.5)
|
|
||||||
}
|
|
||||||
s.positionLock.Unlock()
|
s.positionLock.Unlock()
|
||||||
_ = s.ClosePosition(ctx, fixedpoint.One)
|
_ = s.ClosePosition(ctx, fixedpoint.One)
|
||||||
} else {
|
} else {
|
||||||
|
@ -901,15 +894,14 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
if s.highestPrice > 0 && highf > s.highestPrice {
|
if s.highestPrice > 0 && highf > s.highestPrice {
|
||||||
s.highestPrice = highf
|
s.highestPrice = highf
|
||||||
}
|
}
|
||||||
takeProfitFactor := s.takeProfitFactor.Predict(2)
|
|
||||||
|
|
||||||
if !s.NoRebalance {
|
if !s.NoRebalance {
|
||||||
s.Rebalance(ctx)
|
s.Rebalance(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
balances := s.GeneralOrderExecutor.Session().GetAccount().Balances()
|
balances := s.GeneralOrderExecutor.Session().GetAccount().Balances()
|
||||||
bbgo.Notify("source: %.4f, price: %.4f, driftPred: %.4f, ddriftPred: %.4f, drift[1]: %.4f, ddrift[1]: %.4f, atr: %.4f, takeProfitFact: %.4f, lowf %.4f, highf: %.4f lowest: %.4f highest: %.4f sp %.4f bp %.4f",
|
bbgo.Notify("source: %.4f, price: %.4f, driftPred: %.4f, ddriftPred: %.4f, drift[1]: %.4f, ddrift[1]: %.4f, atr: %.4f, lowf %.4f, highf: %.4f lowest: %.4f highest: %.4f sp %.4f bp %.4f",
|
||||||
sourcef, pricef, driftPred, ddriftPred, drift[1], ddrift[1], atr, takeProfitFactor, lowf, highf, s.lowestPrice, s.highestPrice, s.sellPrice, s.buyPrice)
|
sourcef, pricef, driftPred, ddriftPred, drift[1], ddrift[1], atr, lowf, highf, s.lowestPrice, s.highestPrice, s.sellPrice, s.buyPrice)
|
||||||
// Notify will parse args to strings and process separately
|
// Notify will parse args to strings and process separately
|
||||||
bbgo.Notify("balances: [Base] %s(%vU) [Quote] %s",
|
bbgo.Notify("balances: [Base] %s(%vU) [Quote] %s",
|
||||||
balances[s.Market.BaseCurrency].String(),
|
balances[s.Market.BaseCurrency].String(),
|
||||||
|
@ -927,12 +919,10 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
}
|
}
|
||||||
exitShortCondition := s.sellPrice > 0 && ( //!shortCondition && !longCondition ||
|
exitShortCondition := s.sellPrice > 0 && ( //!shortCondition && !longCondition ||
|
||||||
s.sellPrice*(1.+stoploss) <= highf ||
|
s.sellPrice*(1.+stoploss) <= highf ||
|
||||||
s.trailingCheck(pricef, "short") ||
|
s.trailingCheck(pricef, "short"))
|
||||||
s.sellPrice-atr*takeProfitFactor >= s.lowestPrice)
|
|
||||||
exitLongCondition := s.buyPrice > 0 && ( //!longCondition && !shortCondition ||
|
exitLongCondition := s.buyPrice > 0 && ( //!longCondition && !shortCondition ||
|
||||||
s.buyPrice*(1.-stoploss) >= lowf ||
|
s.buyPrice*(1.-stoploss) >= lowf ||
|
||||||
s.trailingCheck(pricef, "long") ||
|
s.trailingCheck(pricef, "long"))
|
||||||
s.buyPrice+atr*takeProfitFactor <= s.highestPrice)
|
|
||||||
|
|
||||||
if exitShortCondition || exitLongCondition {
|
if exitShortCondition || exitLongCondition {
|
||||||
if err := s.GeneralOrderExecutor.GracefulCancel(ctx); err != nil {
|
if err := s.GeneralOrderExecutor.GracefulCancel(ctx); err != nil {
|
||||||
|
@ -940,15 +930,6 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
s.positionLock.Unlock()
|
s.positionLock.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if exitShortCondition && s.sellPrice > s.lowestPrice {
|
|
||||||
s.takeProfitFactor.Update((s.sellPrice - s.lowestPrice) / atr * 1.5)
|
|
||||||
}
|
|
||||||
if exitLongCondition && s.buyPrice < s.highestPrice {
|
|
||||||
s.takeProfitFactor.Update((s.highestPrice - s.buyPrice) / atr * 1.5)
|
|
||||||
}
|
|
||||||
if s.takeProfitFactor.Last() == 0 {
|
|
||||||
log.Errorf("exit %f %f %v", s.highestPrice, s.lowestPrice, s.takeProfitFactor.Array(10))
|
|
||||||
}
|
|
||||||
s.positionLock.Unlock()
|
s.positionLock.Unlock()
|
||||||
_ = s.ClosePosition(ctx, fixedpoint.One)
|
_ = s.ClosePosition(ctx, fixedpoint.One)
|
||||||
return
|
return
|
||||||
|
@ -976,9 +957,6 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
s.positionLock.Unlock()
|
s.positionLock.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.sellPrice > s.lowestPrice && s.lowestPrice > 0 {
|
|
||||||
s.takeProfitFactor.Update((s.sellPrice - s.lowestPrice) / atr * 1.5)
|
|
||||||
}
|
|
||||||
s.positionLock.Unlock()
|
s.positionLock.Unlock()
|
||||||
quantity := quoteBalance.Available.Div(source)
|
quantity := quoteBalance.Available.Div(source)
|
||||||
createdOrders, err := s.GeneralOrderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
createdOrders, err := s.GeneralOrderExecutor.SubmitOrders(ctx, types.SubmitOrder{
|
||||||
|
@ -1018,9 +996,6 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
s.positionLock.Unlock()
|
s.positionLock.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.buyPrice < s.highestPrice && s.buyPrice > 0 {
|
|
||||||
s.takeProfitFactor.Update((s.highestPrice - s.buyPrice) / atr * 1.5)
|
|
||||||
}
|
|
||||||
s.positionLock.Unlock()
|
s.positionLock.Unlock()
|
||||||
// Cleanup pending StopOrders
|
// Cleanup pending StopOrders
|
||||||
quantity := baseBalance.Available
|
quantity := baseBalance.Available
|
||||||
|
@ -1039,6 +1014,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter
|
s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
s.positionLock.Unlock()
|
||||||
})
|
})
|
||||||
|
|
||||||
bbgo.OnShutdown(func(ctx context.Context, wg *sync.WaitGroup) {
|
bbgo.OnShutdown(func(ctx context.Context, wg *sync.WaitGroup) {
|
||||||
|
@ -1046,6 +1022,11 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
s.Print(&buffer, true, true)
|
s.Print(&buffer, true, true)
|
||||||
|
|
||||||
|
fmt.Fprintln(&buffer, "--- NonProfitable Dates ---")
|
||||||
|
for _, daypnl := range s.TradeStats.IntervalProfits[types.Interval1d].GetNonProfitableIntervals() {
|
||||||
|
fmt.Fprintf(&buffer, "%s\n", daypnl)
|
||||||
|
}
|
||||||
fmt.Fprintln(&buffer, s.TradeStats.BriefString())
|
fmt.Fprintln(&buffer, s.TradeStats.BriefString())
|
||||||
|
|
||||||
os.Stdout.Write(buffer.Bytes())
|
os.Stdout.Write(buffer.Bytes())
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -12,11 +14,12 @@ import (
|
||||||
type IntervalProfitCollector struct {
|
type IntervalProfitCollector struct {
|
||||||
Interval Interval `json:"interval"`
|
Interval Interval `json:"interval"`
|
||||||
Profits *Float64Slice `json:"profits"`
|
Profits *Float64Slice `json:"profits"`
|
||||||
|
Timestamp *Float64Slice `json:"timestamp"`
|
||||||
tmpTime time.Time `json:"tmpTime"`
|
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 {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user