atr计算止盈止损价格

This commit is contained in:
lychiyu 2024-07-30 07:39:46 +08:00
parent f83998420f
commit 13481332fe
2 changed files with 78 additions and 28 deletions

View File

@ -17,14 +17,14 @@ exchangeStrategies:
ccinr: ccinr:
symbols: symbols:
- ARUSDT - ARUSDT
# - BNBUSDT
# - BTCUSDT
# - ETHUSDT
- ORDIUSDT - ORDIUSDT
- OPUSDT - OPUSDT
- OMUSDT - OMUSDT
# - SOLUSDT
- WIFUSDT - WIFUSDT
# - BNBUSDT
# - BTCUSDT
# - ETHUSDT
# - SOLUSDT
# - DYDXUSDT # - DYDXUSDT
# - XRPUSDT # - XRPUSDT
# - PEOPLEUSDT # - PEOPLEUSDT
@ -36,18 +36,23 @@ exchangeStrategies:
# - NOTUSDT # - NOTUSDT
# - ENSUSDT # - ENSUSDT
interval: 1m interval: 1m
nrInterval: 5m
cciInterval: 15m
atrInterval: 1h
nrCount: 4
cciWindow: 20
atrWindow: 14
symbol: ARUSDT symbol: ARUSDT
dryRun: false dryRun: false
nrCount: 4
strictMode: true strictMode: true
cciWindow: 20 longCCI: -180.0
longCCI: -150.0 shortCCI: 180.0
shortCCI: 150.0
leverage: 5.0 leverage: 5.0
profitRange: 0.4% profitRange: 5%
lossRange: 1% lossRange: 1%
amount: 20 amount: 20
placePriceType: 0 placePriceType: 2
lossType: 1
# recalculate: false # recalculate: false
# dry_run: false # dry_run: false
# # quantity: 3 # # quantity: 3

View File

@ -30,11 +30,16 @@ type Strategy struct {
Symbols []string `json:"symbols"` Symbols []string `json:"symbols"`
Interval types.Interval `json:"interval"` Interval types.Interval `json:"interval"`
NRInterval types.Interval `json:"nrInterval"`
CCIInterval types.Interval `json:"cciInterval"`
ATRInterval types.Interval `json:"atrInterval"`
NrCount int `json:"nrCount"` NrCount int `json:"nrCount"`
StrictMode bool `json:"strictMode"` StrictMode bool `json:"strictMode"`
PlacePriceType int `json:"placePriceType"` PlacePriceType int `json:"placePriceType"`
LossType int `json:"lossType"`
DryRun bool `json:"dryRun"` DryRun bool `json:"dryRun"`
CCIWindow int `json:"cciWindow"` CCIWindow int `json:"cciWindow"`
ATRWindow int `json:"atrWindow"`
LongCCI fixedpoint.Value `json:"longCCI"` LongCCI fixedpoint.Value `json:"longCCI"`
ShortCCI fixedpoint.Value `json:"shortCCI"` ShortCCI fixedpoint.Value `json:"shortCCI"`
Leverage fixedpoint.Value `json:"leverage"` Leverage fixedpoint.Value `json:"leverage"`
@ -73,10 +78,13 @@ type Strategy struct {
nr map[string]*indicatorv2.NRStrean nr map[string]*indicatorv2.NRStrean
cci map[string]*indicatorv2.CCIStream cci map[string]*indicatorv2.CCIStream
atr map[string]*indicatorv2.ATRStream
TotalProfit fixedpoint.Value TotalProfit fixedpoint.Value
TotalFree fixedpoint.Value TotalFree fixedpoint.Value
TotalOrderCount int TotalOrderCount int
TotalProfitCount int
TotalLossCount int
} }
func (s *Strategy) ID() string { func (s *Strategy) ID() string {
@ -86,6 +94,9 @@ func (s *Strategy) ID() string {
func (s *Strategy) Subscribe(session *qbtrade.ExchangeSession) { func (s *Strategy) Subscribe(session *qbtrade.ExchangeSession) {
for _, symbol := range s.Symbols { for _, symbol := range s.Symbols {
session.Subscribe(types.KLineChannel, symbol, types.SubscribeOptions{Interval: s.Interval}) session.Subscribe(types.KLineChannel, symbol, types.SubscribeOptions{Interval: s.Interval})
session.Subscribe(types.KLineChannel, symbol, types.SubscribeOptions{Interval: s.CCIInterval})
session.Subscribe(types.KLineChannel, symbol, types.SubscribeOptions{Interval: s.ATRInterval})
session.Subscribe(types.KLineChannel, symbol, types.SubscribeOptions{Interval: s.NRInterval})
session.Subscribe(types.MarketTradeChannel, symbol, types.SubscribeOptions{}) session.Subscribe(types.MarketTradeChannel, symbol, types.SubscribeOptions{})
} }
} }
@ -189,10 +200,32 @@ func (s *Strategy) generateOrders(ctx context.Context, kline types.KLine) ([]typ
// 获取下单价格 // 获取下单价格
placePrice := s.getPlacePrice(ctx, kline) placePrice := s.getPlacePrice(ctx, kline)
// 计算止损止盈价格以ATR为基准或者固定百分比
lossPrice := fixedpoint.Value(0)
profitPrice := fixedpoint.Value(0)
lastATR := s.atr[symbol].Last(0)
if s.TradeType[symbol] == "long" {
if s.LossType == 0 {
lossPrice = placePrice.Sub(placePrice.Mul(s.LossRange))
profitPrice = placePrice.Add(placePrice.Mul(s.ProfitRange))
} else if s.LossType == 1 {
lossPrice = placePrice.Sub(fixedpoint.Value(lastATR))
profitPrice = placePrice.Add(fixedpoint.Value(lastATR * 2))
}
} else if s.TradeType[symbol] == "short" {
if s.LossType == 0 {
lossPrice = placePrice.Add(placePrice.Mul(s.LossRange))
profitPrice = placePrice.Sub(placePrice.Mul(s.ProfitRange))
} else if s.LossType == 1 {
lossPrice = placePrice.Add(fixedpoint.Value(lastATR))
profitPrice = placePrice.Sub(fixedpoint.Value(lastATR * 2))
}
}
// 下单数量 // 下单数量
placeQuantity := s.QuantityOrAmount.CalculateQuantity(placePrice).Mul(s.Leverage) placeQuantity := s.QuantityOrAmount.CalculateQuantity(placePrice).Mul(s.Leverage)
log.Infof(fmt.Sprintf("will place order, price %v, quantity %v", placePrice.Float64(), log.Infof(fmt.Sprintf("will place order, price %v, quantity %v, lossprice %v, profitprice: %v",
placeQuantity.Float64())) placePrice.Float64(), placeQuantity.Float64(), lossPrice.Float64(), profitPrice.Float64()))
s.ShortOrder[symbol] = types.SubmitOrder{ s.ShortOrder[symbol] = types.SubmitOrder{
Symbol: symbol, Symbol: symbol,
@ -208,9 +241,9 @@ func (s *Strategy) generateOrders(ctx context.Context, kline types.KLine) ([]typ
s.ShortProfitOrder[symbol] = types.SubmitOrder{ s.ShortProfitOrder[symbol] = types.SubmitOrder{
Symbol: symbol, Symbol: symbol,
Side: types.SideTypeBuy, Side: types.SideTypeBuy,
Type: types.OrderTypeTakeProfitMarket, Type: types.OrderTypeStopMarket,
PositionSide: types.PositionSideTypeShort, PositionSide: types.PositionSideTypeShort,
StopPrice: placePrice.Sub(placePrice.Mul(s.ProfitRange)), StopPrice: profitPrice,
TimeInForce: types.TimeInForceGTC, TimeInForce: types.TimeInForceGTC,
Market: s.Market, Market: s.Market,
ClosePosition: true, ClosePosition: true,
@ -221,7 +254,7 @@ func (s *Strategy) generateOrders(ctx context.Context, kline types.KLine) ([]typ
Side: types.SideTypeBuy, Side: types.SideTypeBuy,
Type: types.OrderTypeStopMarket, Type: types.OrderTypeStopMarket,
PositionSide: types.PositionSideTypeShort, PositionSide: types.PositionSideTypeShort,
StopPrice: placePrice.Add(placePrice.Mul(s.LossRange)), StopPrice: lossPrice,
TimeInForce: types.TimeInForceGTC, TimeInForce: types.TimeInForceGTC,
Market: s.Market, Market: s.Market,
ClosePosition: true, ClosePosition: true,
@ -241,9 +274,9 @@ func (s *Strategy) generateOrders(ctx context.Context, kline types.KLine) ([]typ
s.LongProfitOrder[symbol] = types.SubmitOrder{ s.LongProfitOrder[symbol] = types.SubmitOrder{
Symbol: symbol, Symbol: symbol,
Side: types.SideTypeSell, Side: types.SideTypeSell,
Type: types.OrderTypeTakeProfitMarket, Type: types.OrderTypeStopMarket,
PositionSide: types.PositionSideTypeLong, PositionSide: types.PositionSideTypeLong,
StopPrice: placePrice.Add(placePrice.Mul(s.ProfitRange)), StopPrice: profitPrice,
TimeInForce: types.TimeInForceGTC, TimeInForce: types.TimeInForceGTC,
Market: s.Market, Market: s.Market,
ClosePosition: true, ClosePosition: true,
@ -254,7 +287,7 @@ func (s *Strategy) generateOrders(ctx context.Context, kline types.KLine) ([]typ
Side: types.SideTypeSell, Side: types.SideTypeSell,
Type: types.OrderTypeStopMarket, Type: types.OrderTypeStopMarket,
PositionSide: types.PositionSideTypeLong, PositionSide: types.PositionSideTypeLong,
StopPrice: placePrice.Sub(placePrice.Mul(s.LossRange)), StopPrice: lossPrice,
TimeInForce: types.TimeInForceGTC, TimeInForce: types.TimeInForceGTC,
Market: s.Market, Market: s.Market,
ClosePosition: true, ClosePosition: true,
@ -325,6 +358,11 @@ func (s *Strategy) notifyProfit(ctx context.Context, symbol string) {
s.TotalProfit = s.TotalProfit.Add(profit) s.TotalProfit = s.TotalProfit.Add(profit)
s.TotalFree = s.TotalFree.Add(free) s.TotalFree = s.TotalFree.Add(free)
s.TotalOrderCount += 1 s.TotalOrderCount += 1
if profit > fixedpoint.Value(0) {
s.TotalProfitCount += 1
} else {
s.TotalLossCount += 1
}
log.Infof(msg) log.Infof(msg)
qbtrade.Notify(msg) qbtrade.Notify(msg)
@ -338,7 +376,8 @@ func (s *Strategy) notifyProfit(ctx context.Context, symbol string) {
// 记得取消订单 // 记得取消订单
s.cancelOrders(ctx, symbol) s.cancelOrders(ctx, symbol)
qbtrade.Notify(fmt.Sprintf("总开仓:%v, 总收益:%v, 总手续费:%v", s.TotalOrderCount, s.TotalProfit.Float64(), s.TotalFree.Float64())) qbtrade.Notify(fmt.Sprintf("总交易次数:%v, 总收益:%v, 总手续费:%v, 盈利次数:%v, 亏损次数:%v",
s.TotalOrderCount, s.TotalProfit.Float64(), s.TotalFree.Float64(), s.TotalProfitCount, s.TotalLossCount))
} }
func (s *Strategy) Run(ctx context.Context, orderExecutor qbtrade.OrderExecutor, session *qbtrade.ExchangeSession) error { func (s *Strategy) Run(ctx context.Context, orderExecutor qbtrade.OrderExecutor, session *qbtrade.ExchangeSession) error {
@ -366,10 +405,13 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor qbtrade.OrderExecutor,
s.nr = make(map[string]*indicatorv2.NRStrean) s.nr = make(map[string]*indicatorv2.NRStrean)
s.cci = make(map[string]*indicatorv2.CCIStream) s.cci = make(map[string]*indicatorv2.CCIStream)
s.atr = make(map[string]*indicatorv2.ATRStream)
s.TotalProfit = fixedpoint.Value(0) s.TotalProfit = fixedpoint.Value(0)
s.TotalFree = fixedpoint.Value(0) s.TotalFree = fixedpoint.Value(0)
s.TotalOrderCount = 0 s.TotalOrderCount = 0
s.TotalProfitCount = 0
s.TotalLossCount = 0
for _, symbol := range s.Symbols { for _, symbol := range s.Symbols {
s.Positions[symbol] = types.NewPositionFromMarket(s.markets[symbol]) s.Positions[symbol] = types.NewPositionFromMarket(s.markets[symbol])
@ -392,18 +434,19 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor qbtrade.OrderExecutor,
qbtrade.Notify("CCINR策略开始执行...") qbtrade.Notify("CCINR策略开始执行...")
for _, symbol := range s.Symbols { for _, symbol := range s.Symbols {
s.nr[symbol] = session.Indicators(symbol).NR(s.Interval, s.NrCount, s.StrictMode) s.nr[symbol] = session.Indicators(symbol).NR(s.NRInterval, s.NrCount, s.StrictMode)
s.cci[symbol] = session.Indicators(symbol).CCI(s.Interval, s.CCIWindow) s.cci[symbol] = session.Indicators(symbol).CCI(s.CCIInterval, s.CCIWindow)
s.atr[symbol] = session.Indicators(symbol).ATR(s.ATRInterval, s.ATRWindow)
s.TradeRetry[symbol] = 0 s.TradeRetry[symbol] = 0
} }
session.MarketDataStream.OnKLineClosed(func(k types.KLine) { session.MarketDataStream.OnKLineClosed(func(k types.KLine) {
for _, symbol := range s.Symbols { for _, symbol := range s.Symbols {
if k.Symbol != symbol || k.Interval != s.Interval { if k.Symbol != symbol {
continue continue
} }
if !s.Traded[symbol] { if !s.Traded[symbol] && k.Interval == s.NRInterval {
// 如若在下一根k线未成交 则取消订单 // 如若在下一根k线未成交 则取消订单
if s.TradeType[symbol] != "" && s.TradeRetry[symbol] > 1 { if s.TradeType[symbol] != "" && s.TradeRetry[symbol] > 1 {
qbtrade.Notify(fmt.Sprintf("交易信号未成交,取消订单: %s", symbol)) qbtrade.Notify(fmt.Sprintf("交易信号未成交,取消订单: %s", symbol))
@ -431,9 +474,9 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor qbtrade.OrderExecutor,
} else { } else {
return return
} }
msg := fmt.Sprintf("交易信号:币种:%s, 方向 %s, 时间: %s, 最高价:%f最低价:%f, CCI: %v", msg := fmt.Sprintf("交易信号:币种:%s, 方向 %s, 时间: %s, 最高价:%f最低价:%f, CCI: %v, ATR: %v",
sym, s.TradeType[sym], s.nr[sym].NrKLine.GetStartTime(), s.nr[sym].NrKLine.High.Float64(), sym, s.TradeType[sym], s.nr[sym].NrKLine.GetStartTime(), s.nr[sym].NrKLine.High.Float64(),
s.nr[sym].NrKLine.Low.Float64(), cciV) s.nr[sym].NrKLine.Low.Float64(), cciV, s.atr[sym].Last(0))
qbtrade.Notify(msg) qbtrade.Notify(msg)
tk := s.nr[sym].NrKLine tk := s.nr[sym].NrKLine
s.placeOrders(ctx, tk) s.placeOrders(ctx, tk)
@ -479,6 +522,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor qbtrade.OrderExecutor,
log.Infof("the order is: %+v,id is %d, symbol is %s, type is %s, status is %s", log.Infof("the order is: %+v,id is %d, symbol is %s, type is %s, status is %s",
order, order.OrderID, orderSymbol, order.Type, order.Status) order, order.OrderID, orderSymbol, order.Type, order.Status)
} }
} else if order.Status == types.OrderStatusCanceled {
log.Infof("canceled order %+v", order)
} }
}) })