mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 01:01:56 +00:00
feature: re-implement heikinashi for elliottwave
This commit is contained in:
parent
4a878b5596
commit
28802dd107
|
@ -25,13 +25,14 @@ exchangeStrategies:
|
|||
elliottwave:
|
||||
symbol: BTCUSDT
|
||||
# kline interval for indicators
|
||||
interval: 3m
|
||||
stoploss: 0.15%
|
||||
interval: 4m
|
||||
stoploss: 0.5%
|
||||
windowATR: 14
|
||||
windowQuick: 3
|
||||
windowSlow: 13
|
||||
source: hl2
|
||||
pendingMinutes: 8
|
||||
windowQuick: 10
|
||||
windowSlow: 96
|
||||
source: hlc3
|
||||
pendingMinutes: 10
|
||||
useHeikinAshi: true
|
||||
|
||||
drawGraph: true
|
||||
graphIndicatorPath: "./indicator.png"
|
||||
|
@ -107,7 +108,7 @@ sync:
|
|||
- BTCUSDT
|
||||
|
||||
backtest:
|
||||
startTime: "2022-08-30"
|
||||
startTime: "2022-08-01"
|
||||
endTime: "2022-09-30"
|
||||
symbols:
|
||||
- BTCUSDT
|
||||
|
@ -115,7 +116,7 @@ backtest:
|
|||
accounts:
|
||||
binance:
|
||||
makerFeeRate: 0.000
|
||||
#takerFeeRate: 0.000
|
||||
takerFeeRate: 0.000
|
||||
balances:
|
||||
BTC: 0
|
||||
USDT: 5000
|
||||
|
|
46
pkg/strategy/elliottwave/heikinashi.go
Normal file
46
pkg/strategy/elliottwave/heikinashi.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
package elliottwave
|
||||
|
||||
import (
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
||||
type HeikinAshi struct {
|
||||
Values []types.KLine
|
||||
size int
|
||||
}
|
||||
|
||||
func NewHeikinAshi(size int) *HeikinAshi {
|
||||
return &HeikinAshi{
|
||||
Values: make([]types.KLine, size),
|
||||
size: size,
|
||||
}
|
||||
}
|
||||
|
||||
func (inc *HeikinAshi) Last() *types.KLine {
|
||||
if len(inc.Values) == 0 {
|
||||
return &types.KLine{}
|
||||
}
|
||||
return &inc.Values[len(inc.Values)-1]
|
||||
}
|
||||
|
||||
func (inc *HeikinAshi) Update(kline types.KLine) {
|
||||
open := kline.Open
|
||||
cloze := kline.Close
|
||||
high := kline.High
|
||||
low := kline.Low
|
||||
lastOpen := inc.Last().Open
|
||||
lastClose := inc.Last().Close
|
||||
|
||||
newClose := open.Add(high).Add(low).Add(cloze).Div(Four)
|
||||
newOpen := lastOpen.Add(lastClose).Div(Two)
|
||||
|
||||
kline.Close = newClose
|
||||
kline.Open = newOpen
|
||||
kline.High = fixedpoint.Max(fixedpoint.Max(high, newOpen), newClose)
|
||||
kline.Low = fixedpoint.Max(fixedpoint.Min(low, newOpen), newClose)
|
||||
inc.Values = append(inc.Values, kline)
|
||||
if len(inc.Values) > inc.size {
|
||||
inc.Values = inc.Values[len(inc.Values)-inc.size:]
|
||||
}
|
||||
}
|
|
@ -48,6 +48,7 @@ type Strategy struct {
|
|||
WindowQuick int `json:"windowQuick"`
|
||||
WindowSlow int `json:"windowSlow"`
|
||||
PendingMinutes int `json:"pendingMinutes"`
|
||||
UseHeikinAshi bool `json:"useHeikinAshi"`
|
||||
|
||||
// whether to draw graph or not by the end of backtest
|
||||
DrawGraph bool `json:"drawGraph"`
|
||||
|
@ -61,8 +62,9 @@ type Strategy struct {
|
|||
*types.ProfitStats `persistence:"profit_stats"`
|
||||
*types.TradeStats `persistence:"trade_stats"`
|
||||
|
||||
ewo *ElliottWave
|
||||
atr *indicator.ATR
|
||||
ewo *ElliottWave
|
||||
atr *indicator.ATR
|
||||
heikinAshi *HeikinAshi
|
||||
|
||||
priceLines *types.Queue
|
||||
|
||||
|
@ -155,12 +157,14 @@ func (s *Strategy) initIndicators(store *bbgo.SerialMarketDataStore) error {
|
|||
return errors.New("klines not exists")
|
||||
}
|
||||
s.startTime = (*klines)[klineLength-1].EndTime.Time()
|
||||
s.heikinAshi = NewHeikinAshi(500)
|
||||
|
||||
for _, kline := range *klines {
|
||||
source := s.GetSource(&kline).Float64()
|
||||
s.ewo.Update(source)
|
||||
s.atr.PushK(kline)
|
||||
s.priceLines.Update(source)
|
||||
s.heikinAshi.Update(kline)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -418,10 +422,17 @@ func (s *Strategy) klineHandler1m(ctx context.Context, kline types.KLine) {
|
|||
}
|
||||
|
||||
func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
||||
s.heikinAshi.Update(kline)
|
||||
source := s.GetSource(&kline)
|
||||
sourcef := source.Float64()
|
||||
s.priceLines.Update(sourcef)
|
||||
s.ewo.Update(sourcef)
|
||||
if s.UseHeikinAshi {
|
||||
source := s.GetSource(s.heikinAshi.Last())
|
||||
sourcef := source.Float64()
|
||||
s.ewo.Update(sourcef)
|
||||
} else {
|
||||
s.ewo.Update(sourcef)
|
||||
}
|
||||
s.atr.PushK(kline)
|
||||
|
||||
if s.Status != types.StrategyStatusRunning {
|
||||
|
@ -437,9 +448,11 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
|||
s.smartCancel(ctx, pricef)
|
||||
|
||||
atr := s.atr.Last()
|
||||
ewo := types.Array(s.ewo, 3)
|
||||
shortCondition := ewo[0] < ewo[1] && ewo[1] > ewo[2] || s.sellPrice == 0 && ewo[0] < ewo[1] && ewo[1] < ewo[2]
|
||||
longCondition := ewo[0] > ewo[1] && ewo[1] < ewo[2] || s.buyPrice == 0 && ewo[0] > ewo[1] && ewo[1] > ewo[2]
|
||||
ewo := types.Array(s.ewo, 4)
|
||||
bull := kline.Close.Compare(kline.Open) > 0
|
||||
|
||||
shortCondition := ewo[0] < ewo[1] && ewo[1] >= ewo[2] && (ewo[1] <= ewo[2] || ewo[2] >= ewo[3]) || s.sellPrice == 0 && ewo[0] < ewo[1] && ewo[1] < ewo[2]
|
||||
longCondition := ewo[0] > ewo[1] && ewo[1] <= ewo[2] && (ewo[1] >= ewo[2] || ewo[2] <= ewo[3]) || s.buyPrice == 0 && ewo[0] > ewo[1] && ewo[1] > ewo[2]
|
||||
|
||||
exitShortCondition := s.sellPrice > 0 && !shortCondition && s.sellPrice*(1.+stoploss) <= highf || s.sellPrice+atr <= sourcef || s.trailingCheck(highf, "short")
|
||||
exitLongCondition := s.buyPrice > 0 && !longCondition && s.buyPrice*(1.-stoploss) >= lowf || s.buyPrice-atr >= sourcef || s.trailingCheck(lowf, "long")
|
||||
|
@ -451,7 +464,7 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
|||
}
|
||||
s.ClosePosition(ctx, fixedpoint.One)
|
||||
}
|
||||
if longCondition {
|
||||
if longCondition && bull {
|
||||
if err := s.GeneralOrderExecutor.GracefulCancel(ctx); err != nil {
|
||||
log.WithError(err).Errorf("cannot cancel orders")
|
||||
return
|
||||
|
@ -487,7 +500,7 @@ func (s *Strategy) klineHandler(ctx context.Context, kline types.KLine) {
|
|||
s.orderPendingCounter[createdOrders[0].OrderID] = s.minutesCounter
|
||||
return
|
||||
}
|
||||
if shortCondition {
|
||||
if shortCondition && !bull {
|
||||
if err := s.GeneralOrderExecutor.GracefulCancel(ctx); err != nil {
|
||||
log.WithError(err).Errorf("cannot cancel orders")
|
||||
return
|
||||
|
|
Loading…
Reference in New Issue
Block a user