Merge pull request #633 from zenixls2/fix/ewo_entry

Fix/ewo entry, backtest
This commit is contained in:
Zenix 2022-05-30 15:47:46 +09:00 committed by GitHub
commit 8652b4e043
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 664 additions and 302 deletions

View File

@ -155,7 +155,7 @@ const ordersToMarkets = (interval: string, orders: Array<Order> | void): Array<M
// var markers = [{ time: data[data.length - 48].time, position: 'aboveBar', color: '#f68410', shape: 'circle', text: 'D' }]; // var markers = [{ time: data[data.length - 48].time, position: 'aboveBar', color: '#f68410', shape: 'circle', text: 'D' }];
for (let i = 0; i < orders.length; i++) { for (let i = 0; i < orders.length; i++) {
let order = orders[i]; let order = orders[i];
let t = order.update_time.getTime() / 1000.0; let t = (order.update_time || order.time).getTime() / 1000.0;
let lastMarker = markers.length > 0 ? markers[markers.length - 1] : null; let lastMarker = markers.length > 0 ? markers[markers.length - 1] : null;
if (lastMarker) { if (lastMarker) {
let remainder = lastMarker.time % intervalSecs; let remainder = lastMarker.time % intervalSecs;
@ -264,7 +264,7 @@ const positionBaseHistoryToLineData = (interval: string, hs: Array<PositionHisto
} }
// ignore duplicated entry // ignore duplicated entry
if (hs[i].time.getTime() === hs[i - 1].time.getTime()) { if (i > 0 && hs[i].time.getTime() === hs[i - 1].time.getTime()) {
continue continue
} }
@ -296,7 +296,7 @@ const positionAverageCostHistoryToLineData = (interval: string, hs: Array<Positi
} }
// ignore duplicated entry // ignore duplicated entry
if (hs[i].time.getTime() === hs[i - 1].time.getTime()) { if (i > 0 && hs[i].time.getTime() === hs[i - 1].time.getTime()) {
continue continue
} }

View File

@ -10,20 +10,29 @@ exchangeStrategies:
- on: binance - on: binance
ewo_dgtrd: ewo_dgtrd:
symbol: MATICUSDT symbol: MATICUSDT
interval: 2h # kline interval for indicators
interval: 15m
# use ema as MA
useEma: false useEma: false
# use sma as MA, used when ema is false
# if both sma and ema are false, use EVMA
useSma: false useSma: false
sigWin: 8 # ewo signal line window size
stoploss: 10% sigWin: 5
# SL percentage from entry price
stoploss: 2%
# use HeikinAshi klines instead of normal OHLC
useHeikinAshi: true useHeikinAshi: true
# disable SL when short
disableShortStop: false disableShortStop: false
#stops: # disable SL when long
#- trailingStop: disableLongStop: false
# callbackRate: 5.1% # CCI Stochastic Indicator high filter
# closePosition: 20% ccistochFilterHigh: 80
# minProfit: 1% # CCI Stochastic Indicator low filter
# interval: 1m ccistochFilterLow: 20
# virtual: true # print record exit point in log messages
record: false
sync: sync:
userDataStream: userDataStream:
@ -36,7 +45,7 @@ sync:
backtest: backtest:
startTime: "2022-05-01" startTime: "2022-05-01"
endTime: "2022-05-11" endTime: "2022-05-27"
symbols: symbols:
- MATICUSDT - MATICUSDT
sessions: [binance] sessions: [binance]
@ -45,5 +54,5 @@ backtest:
#makerFeeRate: 0 #makerFeeRate: 0
#takerFeeRate: 15 #takerFeeRate: 15
balances: balances:
MATIC: 5000.0 MATIC: 000.0
USDT: 10000 USDT: 15000.0

View File

@ -281,11 +281,11 @@ func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) {
return e.markets, nil return e.markets, nil
} }
func (e Exchange) QueryDepositHistory(ctx context.Context, asset string, since, until time.Time) (allDeposits []types.Deposit, err error) { func (e *Exchange) QueryDepositHistory(ctx context.Context, asset string, since, until time.Time) (allDeposits []types.Deposit, err error) {
return nil, nil return nil, nil
} }
func (e Exchange) QueryWithdrawHistory(ctx context.Context, asset string, since, until time.Time) (allWithdraws []types.Withdraw, err error) { func (e *Exchange) QueryWithdrawHistory(ctx context.Context, asset string, since, until time.Time) (allWithdraws []types.Withdraw, err error) {
return nil, nil return nil, nil
} }

View File

@ -410,6 +410,15 @@ func (m *SimplePriceMatching) SellToPrice(price fixedpoint.Value) (closedOrders
func (m *SimplePriceMatching) processKLine(kline types.KLine) { func (m *SimplePriceMatching) processKLine(kline types.KLine) {
m.CurrentTime = kline.EndTime.Time() m.CurrentTime = kline.EndTime.Time()
m.LastKLine = kline m.LastKLine = kline
if m.LastPrice.IsZero() {
m.LastPrice = kline.Open
} else {
if m.LastPrice.Compare(kline.Open) > 0 {
m.SellToPrice(kline.Open)
} else {
m.BuyToPrice(kline.Open)
}
}
switch kline.Direction() { switch kline.Direction() {
case types.DirectionDown: case types.DirectionDown:

View File

@ -34,7 +34,6 @@ func (s *BacktestService) SyncKLineByInterval(ctx context.Context, exchange type
if err := s.BatchInsert(klines); err != nil { if err := s.BatchInsert(klines); err != nil {
return err return err
} }
count += len(klines) count += len(klines)
} }
log.Debugf("inserted klines %s %s data: %d", symbol, interval.String(), count) log.Debugf("inserted klines %s %s data: %d", symbol, interval.String(), count)
@ -321,9 +320,12 @@ func (s *BacktestService) BatchInsert(kline []types.KLine) error {
sql := fmt.Sprintf("INSERT INTO `%s` (`exchange`, `start_time`, `end_time`, `symbol`, `interval`, `open`, `high`, `low`, `close`, `closed`, `volume`, `quote_volume`, `taker_buy_base_volume`, `taker_buy_quote_volume`)"+ sql := fmt.Sprintf("INSERT INTO `%s` (`exchange`, `start_time`, `end_time`, `symbol`, `interval`, `open`, `high`, `low`, `close`, `closed`, `volume`, `quote_volume`, `taker_buy_base_volume`, `taker_buy_quote_volume`)"+
" values (:exchange, :start_time, :end_time, :symbol, :interval, :open, :high, :low, :close, :closed, :volume, :quote_volume, :taker_buy_base_volume, :taker_buy_quote_volume); ", tableName) " values (:exchange, :start_time, :end_time, :symbol, :interval, :open, :high, :low, :close, :closed, :volume, :quote_volume, :taker_buy_base_volume, :taker_buy_quote_volume); ", tableName)
_, err := s.DB.NamedExec(sql, kline) tx := s.DB.MustBegin()
if _, err := tx.NamedExec(sql, kline); err != nil {
return err return err
} }
return tx.Commit()
}
func (s *BacktestService) _deleteDuplicatedKLine(k types.KLine) error { func (s *BacktestService) _deleteDuplicatedKLine(k types.KLine) error {

View File

@ -0,0 +1,86 @@
package ewoDgtrd
import (
"fmt"
"math"
"github.com/c9s/bbgo/pkg/types"
)
type Queue struct {
arr []float64
size int
}
func NewQueue(size int) *Queue {
return &Queue{
arr: make([]float64, 0, size),
size: size,
}
}
func (inc *Queue) Last() float64 {
if len(inc.arr) == 0 {
return 0
}
return inc.arr[len(inc.arr)-1]
}
func (inc *Queue) Index(i int) float64 {
if len(inc.arr)-i-1 < 0 {
return 0
}
return inc.arr[len(inc.arr)-i-1]
}
func (inc *Queue) Length() int {
return len(inc.arr)
}
func (inc *Queue) Update(v float64) {
inc.arr = append(inc.arr, v)
if len(inc.arr) > inc.size {
inc.arr = inc.arr[len(inc.arr)-inc.size:]
}
}
type HeikinAshi struct {
Close *Queue
Open *Queue
High *Queue
Low *Queue
Volume *Queue
}
func NewHeikinAshi(size int) *HeikinAshi {
return &HeikinAshi{
Close: NewQueue(size),
Open: NewQueue(size),
High: NewQueue(size),
Low: NewQueue(size),
Volume: NewQueue(size),
}
}
func (s *HeikinAshi) Print() string {
return fmt.Sprintf("Heikin c: %.3f, o: %.3f, h: %.3f, l: %.3f, v: %.3f",
s.Close.Last(),
s.Open.Last(),
s.High.Last(),
s.Low.Last(),
s.Volume.Last())
}
func (inc *HeikinAshi) Update(kline types.KLine) {
open := kline.Open.Float64()
cloze := kline.Close.Float64()
high := kline.High.Float64()
low := kline.Low.Float64()
newClose := (open + high + low + cloze) / 4.
newOpen := (inc.Open.Last() + inc.Close.Last()) / 2.
inc.Close.Update(newClose)
inc.Open.Update(newOpen)
inc.High.Update(math.Max(math.Max(high, newOpen), newClose))
inc.Low.Update(math.Min(math.Min(low, newOpen), newClose))
inc.Volume.Update(kline.Volume.Float64())
}

File diff suppressed because it is too large Load Diff

View File

@ -9,3 +9,8 @@ func tryLock(lock *sync.RWMutex) bool {
lock.Lock() lock.Lock()
return true return true
} }
func tryRLock(lock *sync.RWMutex) bool {
lock.RLock()
return true
}

View File

@ -8,3 +8,7 @@ import "sync"
func tryLock(lock *sync.RWMutex) bool { func tryLock(lock *sync.RWMutex) bool {
return lock.TryLock() return lock.TryLock()
} }
func tryRLock(lock *sync.RWMutex) bool {
return lock.TryRLock()
}

View File

@ -122,7 +122,7 @@ func (p *Position) NewProfit(trade Trade, profit, netProfit fixedpoint.Value) Pr
func (p *Position) NewClosePositionOrder(percentage fixedpoint.Value) *SubmitOrder { func (p *Position) NewClosePositionOrder(percentage fixedpoint.Value) *SubmitOrder {
base := p.GetBase() base := p.GetBase()
quantity := base.Mul(percentage) quantity := base.Mul(percentage).Abs()
if quantity.Compare(p.Market.MinQuantity) < 0 { if quantity.Compare(p.Market.MinQuantity) < 0 {
return nil return nil
} }