mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 00:05:15 +00:00
Merge pull request #633 from zenixls2/fix/ewo_entry
Fix/ewo entry, backtest
This commit is contained in:
commit
8652b4e043
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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,8 +320,11 @@ 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()
|
||||||
return err
|
if _, err := tx.NamedExec(sql, kline); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BacktestService) _deleteDuplicatedKLine(k types.KLine) error {
|
func (s *BacktestService) _deleteDuplicatedKLine(k types.KLine) error {
|
||||||
|
|
86
pkg/strategy/ewoDgtrd/heikinashi.go
Normal file
86
pkg/strategy/ewoDgtrd/heikinashi.go
Normal 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
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user