initial
This commit is contained in:
176
trade/binance_positions.go
Normal file
176
trade/binance_positions.go
Normal file
@@ -0,0 +1,176 @@
|
||||
package trade
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"git.apinb.com/bsm-sdk/core/utils"
|
||||
"git.apinb.com/quant/strategy/internal/impl"
|
||||
"git.apinb.com/quant/strategy/internal/models"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
var (
|
||||
PositionsTotal int = 0
|
||||
)
|
||||
|
||||
func GetPosSummary(PlanKeyName string) []string {
|
||||
cacheBytes, err := impl.RedisService.Client.Get(impl.RedisService.Ctx, PlanKeyName+".PosSummary").Bytes()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
data := strings.Split(string(cacheBytes), ",")
|
||||
// log.Println("GetPosSummary", PlanKeyName+".PosSummary", data)
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func GetPosSymbols(PlanKeyName string) []string {
|
||||
cacheBytes, err := impl.RedisService.Client.Get(impl.RedisService.Ctx, PlanKeyName+".PosSummary").Bytes()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
data := strings.Split(string(cacheBytes), ",")
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
symbols := make([]string, 0)
|
||||
for _, row := range data {
|
||||
symbols = append(symbols, strings.Split(row, ".")[0])
|
||||
}
|
||||
|
||||
return utils.ArrayRemoveRepeatString(symbols)
|
||||
}
|
||||
|
||||
func ExistsPosition(PlanKeyName string, symbol string) PositionStatus {
|
||||
data := GetPosSummary(PlanKeyName)
|
||||
if len(data) == 0 {
|
||||
return NoPositions
|
||||
}
|
||||
|
||||
LongExists := utils.ArrayInString(symbol+".LONG", data)
|
||||
ShortExists := utils.ArrayInString(symbol+".SHORT", data)
|
||||
|
||||
if LongExists && ShortExists {
|
||||
return BothPositions
|
||||
}
|
||||
|
||||
//log.Println("ExistsPosition", symbol, LongExists, ShortExists)
|
||||
return GetPositionStats(LongExists, ShortExists)
|
||||
}
|
||||
|
||||
func GetPositions(PlanKeyName string, symbol string) ([]*models.QuantOrders, error) {
|
||||
cacheBytes, err := impl.RedisService.Client.Get(impl.RedisService.Ctx, PlanKeyName+".PosOrders").Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var orders map[string][]*models.QuantOrders
|
||||
err = msgpack.Unmarshal(cacheBytes, &orders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, ok := orders[symbol]; !ok {
|
||||
return nil, fmt.Errorf("%s %s Not Found Position", PlanKeyName, symbol)
|
||||
}
|
||||
|
||||
return orders[symbol], nil
|
||||
|
||||
}
|
||||
|
||||
func RefreshPositions(p *Spec) (map[string][]*models.QuantOrders, error) {
|
||||
orders := make(map[string][]*models.QuantOrders, 0)
|
||||
var summary []string
|
||||
|
||||
switch p.Api.Exchange {
|
||||
case "BINANCE":
|
||||
summary, orders = p.BinanceClient.GetPositions()
|
||||
break
|
||||
case "BITGET":
|
||||
//summary, orders, _ := GetPositions_Bitget(api)
|
||||
break
|
||||
default:
|
||||
return nil, fmt.Errorf("Not Found Exchange", p.Api.Exchange)
|
||||
}
|
||||
|
||||
// 统地订单数量
|
||||
PositionsTotal = len(summary)
|
||||
if PositionsTotal == 0 {
|
||||
impl.RedisService.Client.Del(impl.RedisService.Ctx, p.PlanKeyName+".PosSummary").Result()
|
||||
impl.RedisService.Client.Del(impl.RedisService.Ctx, p.PlanKeyName+".PosOrders").Result()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
_, err := impl.RedisService.Client.Set(impl.RedisService.Ctx, p.PlanKeyName+".PosSummary", strings.Join(summary, ","), 0).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 序列化为 MessagePack
|
||||
ordersPack, _ := msgpack.Marshal(orders)
|
||||
_, err = impl.RedisService.Client.Set(impl.RedisService.Ctx, p.PlanKeyName+".PosOrders", ordersPack, 0).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
func (bn *BinanceClient) GetPositions() ([]string, map[string][]*models.QuantOrders) {
|
||||
data, err := bn.Futures.NewGetPositionRiskV3Service().Do(context.Background())
|
||||
|
||||
if err != nil {
|
||||
log.Println("GetPositions_Binance", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// jsonBytes, _ := json.Marshal(data)
|
||||
// fmt.Println(string(jsonBytes))
|
||||
|
||||
positionData := make(map[string][]*models.QuantOrders, 0)
|
||||
var PositionSummary []string
|
||||
|
||||
for _, row := range data {
|
||||
amt := utils.String2Float64(row.PositionAmt)
|
||||
if amt == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
side := strings.ToUpper(row.PositionSide)
|
||||
PositionSummary = append(PositionSummary, row.Symbol+"."+side)
|
||||
|
||||
record := &models.QuantOrders{
|
||||
Symbol: row.Symbol,
|
||||
Side: side,
|
||||
OpenPrice: utils.String2Float64(row.BreakEvenPrice), // 开仓成本价
|
||||
Volume: math.Abs(utils.String2Float64(row.PositionAmt)), // 交易币成交数量
|
||||
MarginSize: utils.String2Float64(row.InitialMargin), // 计价币成交数量
|
||||
Status: "1", // 成交
|
||||
}
|
||||
|
||||
/* TODO: 暂时不计算包括成本的均价
|
||||
// 总成本 = (开仓价格 *开仓数量)+手续费
|
||||
decOpenPrice := decimal.NewFromFloat(record.OpenPrice)
|
||||
decVolume := decimal.NewFromFloat(record.Volume)
|
||||
decFee := decimal.NewFromFloat(record.Fee)
|
||||
totalCost := decOpenPrice.Mul(decVolume)
|
||||
totalCost = totalCost.Add(decFee)
|
||||
|
||||
// 均价 = 总成本 / 总开仓数量
|
||||
record.AvgPrice, _ = totalCost.Div(decVolume).Float64()
|
||||
*/
|
||||
|
||||
positionData[row.Symbol] = append(positionData[row.Symbol], record)
|
||||
}
|
||||
|
||||
return PositionSummary, positionData
|
||||
}
|
||||
Reference in New Issue
Block a user