Skip to content

Commit

Permalink
オプティマルFの実装
Browse files Browse the repository at this point in the history
  • Loading branch information
T.K committed Feb 8, 2024
1 parent 4c07a23 commit db533a6
Show file tree
Hide file tree
Showing 12 changed files with 330 additions and 75 deletions.
4 changes: 2 additions & 2 deletions REDME.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ BOTはバックテスト機能から本番環境へのスイッチを容易に
それは、トレードの実行に関わる機能で切り替えるだけで行えます
BOTはロングとショートの両方のトレードに対応した、精密なバックテスト機能を持っています
BOTは、バックテスト結果を詳細に出力する、アナリティクス機能を持っています
BOTは、ストラテジーを容易に追加、拡張することができます
BOTは、ストラテジーを容易に追加、変更することができます
BOTはオリジナルインジケーターを容易に追加、拡張することができます
BOTはトレードの実行の機能を制御するためのマネーマネジメント機能を持っています
BOTは一人のトレーダーとして振る舞い、Long,Short,Exit,Stayの4つの行動を取ります。
Expand Down Expand Up @@ -86,4 +86,4 @@ GORM
TA-LIB

=======
>>>>>>> f2368b9e69670deb7cada702d1a07d48385c2c42

11 changes: 6 additions & 5 deletions config.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@



#バックテストの基本設定 startとendの月は必ず二桁になるように。
assetName: "LINKUSDT"
duration: "30m"
start: "20211101"
end: "20221130"
#バックテストの基本設定
assetName: "ATOMUSDT"
duration: "5m"
start: "20200801"
end: "20230730"
simpleInterest: true
10 changes: 5 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ func main() {

// strategey.RunEmaOptimize()
// strategey.RunSTOptimize()
strategey.RunDonchainOptimize()
// strategey.RunDonchainOptimize()

// strategey.RunBetterRsiOptimize()

// strategey.DonchainBacktest()
// strategey.EmaBacktest()
strategey.DonchainBacktest()
strategey.EmaBacktest()
strategey.SuperTrendBacktest()
strategey.RSIBryyrtBacktest()

// strategey.DonchainBacktest()
// strategey.SuperTrendBacktest()
// strategey.EmaBacktest()
// strategey.RunBacktestST()
// strategey.RunRsi2Optimize()
Expand Down
26 changes: 26 additions & 0 deletions pkg/analytics/profit_and_loss.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,29 @@ func GainPainRatio(s *execute.SignalEvents) float64 {
return gainPainRatio

}

func ReturnProfitLoss(s *execute.SignalEvents) []float64 {
if s == nil {
return nil
}
var pl []float64 // profit or loss slice
var buyPrice float64

if s.Signals == nil || len(s.Signals) == 0 {
return nil
}
for _, signal := range s.Signals {

if signal.Side != "BUY" && signal.Side != "SELL" {
return nil
}
if signal.Side == "BUY" {
buyPrice = signal.Price
} else if signal.Side == "SELL" && buyPrice != 0 {
pl = append(pl, (signal.Price-buyPrice)*signal.Size) // append the profit or loss of the trade to the slice
buyPrice = 0 // Reset buy price after a sell
}
}

return pl
}
1 change: 1 addition & 0 deletions pkg/config/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Config struct {
Dration string `yaml:"duration"`
Start string `yaml:"start"`
End string `yaml:"end"`
Simple bool `yaml:"simpleInterest"`
}

func Yaml() (Config, error) {
Expand Down
149 changes: 149 additions & 0 deletions pkg/management/risk/optimal_f.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package risk

import (
"math"
"v1/pkg/analytics"
"v1/pkg/execute"
)

// func CalculateHPR(f float64, pl []float64) float64 {
// if len(pl) == 0 {
// return 0.0
// }

// maxLoss := pl[0] // 最初の損益を仮の最大損失とする
// for _, p := range pl {
// maxLoss = math.Min(maxLoss, p) // plの中で一番小さい値を最大損失とする
// }

// if maxLoss == 0 {
// return 0.0 // 資産が0になった場合はHPRも0になる
// }

// return 1 + f*(-pl[0]/maxLoss) // pl[0]は最初の損益
// }

// func CalculateTWR(f float64, pl []float64) float64 {
// if len(pl) == 0 {
// return 0.0
// }

// maxLoss := pl[0] // 最初の損益を仮の最大損失とする
// for _, p := range pl {
// maxLoss = math.Min(maxLoss, p) // plの中で一番小さい値を最大損失とする
// }

// twr := 1.0
// for _, p := range pl {
// if maxLoss != 0 {
// twr *= (1 + f*(-p/maxLoss)) // maxLossは最大損失
// } else {
// twr = 0.0 // 資産が0になった場合はTWRも0になる
// }

// }

// return twr
// }

// func OptimalF(s *execute.SignalEvents) float64 {
// maxF := 0.0
// maxGeomMean := 0.0

// plSlice := analytics.ReturnProfitLoss(s)
// // maxLossTrade, _ := analytics.MaxLossTrade(s)

// low := 0.000
// high := 1.000
// epsilon := 0.0001

// for high-low > epsilon {
// f := (low + high) / 2
// hpr := CalculateHPR(f, plSlice)
// twr := CalculateTWR(f, plSlice)

// geomMean := math.Pow(twr, 1/float64(len(plSlice)))

// if geomMean > maxGeomMean {
// maxGeomMean = geomMean
// maxF = f
// }

// // fの値を更新する
// // HPRとTWRの関数はfに対して凸関数なので、
// // 幾何平均が最大になるfは、HPRとTWRが等しくなるfに近い
// if hpr > twr {
// low = f
// } else {
// high = f
// }
// }

// return maxF
// }

func CalculateHPR(f float64, pl []float64) float64 {
if len(pl) == 0 {
return 0.0
}

plMin := pl[0]
for _, p := range pl {
if p < plMin {
plMin = p
}
}

if plMin == 0 {
return 1 + f*(pl[len(pl)-1]/0.01)
}

return 1 + f*(pl[len(pl)-1]/plMin)
}

func CalculateTWR(f float64, pl []float64) float64 {
if len(pl) == 0 {
return 0.0
}

plMin := pl[0]
for _, p := range pl {
if p < plMin {
plMin = p
}
}

twr := 1.0
for _, p := range pl {
if plMin != 0 {
twr *= (1 + f*(p/-plMin))
} else {
twr *= (1 + f*(p/-f))
}

}

return twr
}

func OptimalF(s *execute.SignalEvents) float64 {
maxF := 0.0
maxGeomMean := 0.0

plSlice := analytics.ReturnProfitLoss(s)
// maxLossTrade, _ := analytics.MaxLossTrade(s)

for f := 0.01; f < 1; f += 0.01 {
// hpr := CalculateHPR(f, plSlice)
twr := CalculateTWR(f, plSlice)

geomMean := math.Pow(twr, 1/float64(len(plSlice)))

if geomMean > maxGeomMean {
maxGeomMean = geomMean
maxF = f
}
}

return maxF
}
13 changes: 8 additions & 5 deletions pkg/strategey/donchain_choppy.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
// func getStrageyNameDonchain() string {
// return "DBO"
// }
var simple bool = false

func (df *DataFrameCandle) DonchainChoppyStrategy(period int, choppy int, duration int, account *trader.Account, simple bool) *execute.SignalEvents {
var StrategyName = "DBO_CHOPPY"
Expand All @@ -36,7 +35,6 @@ func (df *DataFrameCandle) DonchainChoppyStrategy(period int, choppy int, durati

buySize := 0.0
buyPrice := 0.0
// simlpeAccountBalance := 1000.0
slRatio := 0.9
isHolding := false

Expand Down Expand Up @@ -144,8 +142,8 @@ func (df *DataFrameCandle) OptimizeDonchainChoppyGoroutin() (performance float64
// return
// }

// pf := analytics.SortinoRatio(signalEvents, 0.02)
pf := analytics.SQN(signalEvents)
pf := analytics.SortinoRatio(signalEvents, 0.02)
// pf := analytics.SQN(signalEvents)
mu.Lock()
if performance < pf {
performance = pf
Expand Down Expand Up @@ -178,6 +176,11 @@ func RunDonchainOptimize() {
df.Signal = df.DonchainChoppyStrategy(bestPeriod, bestChoppy, bestDuration, account, simple)
Result(df.Signal)

} else {
fmt.Println("💸マイナスです")
df.Signal = df.DonchainChoppyStrategy(bestPeriod, bestChoppy, bestDuration, account, simple)
Result(df.Signal)

}

}
Expand All @@ -186,6 +189,6 @@ func DonchainBacktest() {

df, account, _ := RadyBacktest()

df.Signal = df.DonchainChoppyStrategy(5, 14, 10, account, simple)
df.Signal = df.DonchainChoppyStrategy(223, 11, 30, account, simple)
Result(df.Signal)
}
48 changes: 35 additions & 13 deletions pkg/strategey/ema_choppy.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/markcheno/go-talib"
)

func (df *DataFrameCandle) EmaChoppyStrategy(period1, period2 int, choppy int, duration int, account *trader.Account) *execute.SignalEvents {
func (df *DataFrameCandle) EmaChoppyStrategy(period1, period2 int, choppy int, duration int, account *trader.Account, simple bool) *execute.SignalEvents {

var StrategyName = "EMA_CHOPPY"
lenCandles := len(df.Candles)
Expand All @@ -21,6 +21,8 @@ func (df *DataFrameCandle) EmaChoppyStrategy(period1, period2 int, choppy int, d
}
signalEvents := execute.NewSignalEvents()

c := df.Closes()

emaValue1 := talib.Ema(df.Hlc3(), period1)
emaValue2 := talib.Ema(df.Hlc3(), period2)
// rsiValue := talib.Rsi(df.Closes(), 14)
Expand All @@ -39,26 +41,41 @@ func (df *DataFrameCandle) EmaChoppyStrategy(period1, period2 int, choppy int, d

if emaValue1[i-1] < emaValue2[i-1] && emaValue1[i] >= emaValue2[i] && choppyEma[i] > 50 && !isBuyHolding {

accountBalance := account.GetBalance()
// fee := 1 - 0.01

buySize = account.TradeSize(riskSize) / df.Candles[i].Close
buyPrice = df.Candles[i].Close
if account.Buy(df.Candles[i].Close, buySize) {
if simple {
buySize = account.SimpleTradeSize(1)
buyPrice = c[i]
accountBalance := account.GetBalance()

signalEvents.Buy(StrategyName, df.AssetName, df.Duration, df.Candles[i].Date, df.Candles[i].Close, buySize, accountBalance, false)
isBuyHolding = true

} else {
buySize = account.TradeSize(riskSize) / df.Candles[i].Close
buyPrice = c[i]
accountBalance := account.GetBalance()
if account.Buy(df.Candles[i].Close, buySize) {
signalEvents.Buy(StrategyName, df.AssetName, df.Duration, df.Candles[i].Date, df.Candles[i].Close, buySize, accountBalance, false)
isBuyHolding = true
}
}
}
if emaValue1[i-1] > emaValue2[i-1] && emaValue1[i] <= emaValue2[i] || (df.Candles[i].Close <= buyPrice*slRatio) && isBuyHolding {
accountBalance := account.GetBalance()
if account.Sell(df.Candles[i].Close) {
if simple {
accountBalance := 1000.0

signalEvents.Sell(StrategyName, df.AssetName, df.Duration, df.Candles[i].Date, df.Candles[i].Close, buySize, accountBalance, false)
isBuyHolding = false
buySize = 0.0
account.PositionSize = buySize

} else {
accountBalance := account.GetBalance()
if account.Sell(df.Candles[i].Close) {
signalEvents.Sell(StrategyName, df.AssetName, df.Duration, df.Candles[i].Date, df.Candles[i].Close, buySize, accountBalance, false)
isBuyHolding = false
buySize = 0.0
account.PositionSize = buySize

}
}
}
}
Expand Down Expand Up @@ -91,7 +108,7 @@ func (df *DataFrameCandle) OptimizeEmaChoppy() (performance float64, bestPeriod1
go func(period1 int, period2 int, choppy int, duration int) {
defer wg.Done()
account := trader.NewAccount(1000) // Move this line inside the goroutine
signalEvents := df.EmaChoppyStrategy(period1, period2, choppy, duration, account)
signalEvents := df.EmaChoppyStrategy(period1, period2, choppy, duration, account, simple)

if signalEvents == nil {
return
Expand Down Expand Up @@ -154,7 +171,12 @@ func RunEmaOptimize() {

if performance > 0 {

df.Signal = df.EmaChoppyStrategy(bestPeriod1, bestPeriod2, bestChoppy, bestDuration, account)
df.Signal = df.EmaChoppyStrategy(bestPeriod1, bestPeriod2, bestChoppy, bestDuration, account, simple)
Result(df.Signal)

} else {
fmt.Println("💸マイナスです")
df.Signal = df.EmaChoppyStrategy(bestPeriod1, bestPeriod2, bestChoppy, bestDuration, account, simple)
Result(df.Signal)

}
Expand All @@ -165,7 +187,7 @@ func EmaBacktest() {

df, account, _ := RadyBacktest()

df.Signal = df.EmaChoppyStrategy(11, 13, 13, 20, account)
df.Signal = df.EmaChoppyStrategy(13, 33, 13, 30, account, simple)
Result(df.Signal)

}
Loading

0 comments on commit db533a6

Please sign in to comment.