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 }