package data import ( "context" "encoding/json" "github.com/go-xorm/xorm" "github.com/shopspring/decimal" "matchmaking-system/internal/biz/structure" "matchmaking-system/internal/data/socket/publicData" "matchmaking-system/internal/data/tradedeal/share" "matchmaking-system/internal/data/tradedeal/virtual" "matchmaking-system/internal/pkg/flags" "matchmaking-system/internal/pkg/logging/applogger" "matchmaking-system/internal/pkg/logging/common" "matchmaking-system/internal/pkg/setting" "matchmaking-system/internal/pkg/utils" "time" orders "matchmaking-system/internal/data/convert" models "matchmaking-system/internal/pkg/model" ) // GetBotStockBrlTradeList // // @Description: 巴西股订单列表查询 // @receiver uo // @param ctx // @param pageSize // @param pageCount // @param userId // @param status // @return []*models.BotStockBrlTrade // @return int64 // @return error func (uo *userOrderRepo) GetBotStockBrlTradeList(ctx context.Context, pageSize, pageCount, userId, status int64) ([]*models.BotStockBrlTrade, int64, error) { totalCount, err := uo.data.mysqlDB.Table(flags.BotStockBrlTrade). Where("user_id = ?", userId). Where("status = ?", status). Count() if err != nil { return nil, 0, flags.ErrMySqlDB } if totalCount == 0 { return nil, 0, nil } var stockList []*models.BotStockBrlTrade if err = uo.data.mysqlDB.Table(flags.BotStockBrlTrade). Where("user_id = ?", userId). Where("status = ?", status). Limit(int(pageSize), int(pageCount)). Desc(GetOrderByStatusSort(status)). Find(&stockList); err != nil { return nil, 0, flags.ErrMySqlDB } var stockUpdateList []*models.BotStockBrlTrade for _, value := range stockList { value.KeepDecimal = GetKeepDecimal(flags.StockBRLSystemSetUpKey, value.StockId) value.StockName = GetStockName(flags.StockBRLSystemSetUpKey, value.StockId) stockUpdateList = append(stockUpdateList, value) } return stockUpdateList, totalCount, nil } // PlacingStockBrlOrders // // @Description: 巴西股下单 // @receiver uo // @param ctx // @param userId // @param order // @return string // @return error func (uo *userOrderRepo) PlacingStockBrlOrders(ctx context.Context, userId int64, order structure.ShareOrder) (string, error) { // 1、通知下单订阅 symbol := order.StockId timeValue := QuerySystemCache(flags.ShareBrlMarketType) // 市场开闭盘时间 if !utils.CheckInPlateTime(timeValue) { return flags.SetNull, flags.ErrStopTread } SubscribeBrlHSetCodeList(symbol, false) // 同步写入股票列表缓存 SubscribeBrlCloseNewPrice(symbol) // 同步股票实时行情价 // 判定是否存在欠款订单 userIdMap, _ := GetBotUserArrears(ctx) _, isOk := userIdMap[userId] if isOk { return flags.ErrPublicServe.Error(), nil } order = PryNumInit(order) // 杠杆初始化 subKey := publicData.SymbolCache(flags.Brl, symbol, flags.TradeTypePrice) // 市场系统设置 if CheckGlobalTread(flags.BrlMarket) { return flags.SetNull, flags.ErrStopTread } // 全局设置停止交易操作 var blockTime time.Time var priceNew, userKey, adminKey string if !CheckTypeStatus(order.Type) { userKey = setting.ShareBrlSubscribe adminKey = setting.AdminShareBrlSubscribe } else { // 判定:1、是否开启股票交易 2、是否在交易时间内 3、是否达到最小交易量 check, openPrice, minNum, endTime := CheckBlockTread(flags.BrlBlk, symbol) if check { return flags.SetNull, flags.ErrShareSeven } if minNum > utils.StringToInt(order.OrderNumber) { return flags.SetNull, flags.ErrShareSix } priceNew = openPrice // 开仓价格 blockTime = endTime // 平仓时间 userKey = setting.ShareBlkSubscribe adminKey = setting.AdminShareBlkSubscribe } flatRatio := GetCacheForcedClosure(flags.StockBRLSystemSetUpKey, symbol) // 设置强平阈值 leverStatus := SystemShareMarketLeverStatus(flags.StockMarketList, flags.BrlMarket, userId) // 股票市场系统设置 system := &structure.ShareSystem{ StrongFlatRatio: flatRatio.String(), // 强平阈值 Status: leverStatus.Status, // 股杠杆状态 StockMin: leverStatus.StockMin, // 开启杠杆的最小值 LevelMin: leverStatus.LevelMin, // 杠杆最小值 LevelMax: leverStatus.LevelMax, // 杠杆最大值 UserStatus: leverStatus.UserStatus, // 用户开启状态 } order.System = system // 2、股票下单判定 // 下单判定设置(false无设置|true止盈止损) checkBool, stopWinPrice, stopLossPrice, err := StockBrlVoteStopType(order) if err != nil { applogger.Error("%v PlacingStockBrlOrders.StockBrlVoteStopType:%v", common.ErrShareBrl, err) return flags.SetNull, err } // 下单判定设置(限价|市价) limitOrMarketPrice, err := uo.StockBrlVoteDealType(order) if err != nil { applogger.Error("%v PlacingStockBrlOrders.StockBrlVoteDealType:%v", common.ErrShareBrl, err) return flags.SetNull, err } // 下单判定设置(买涨|买跌) if err = uo.VoteTradeType(order.TradeType, stopWinPrice, stopLossPrice, limitOrMarketPrice, checkBool); err != nil { applogger.Error("%v PlacingStockBrlOrders.VoteTradeType:%v", common.ErrShareBrl, err) return flags.SetNull, err } // 3、订单持久化录入(并处理资产信息) pryNum := SystemDealWithLever(order) orderId, err := uo.StockBrlOrderWriteDB(ctx, userId, order, limitOrMarketPrice, pryNum) if err != nil || len(orderId) == 0 { applogger.Error("%v PlacingStockBrlOrders.StockBrlOrderWriteDB:%v", common.ErrShareBrl, err) return flags.SetNull, err } // 4、处理订单信息 chg := GetShareChgBrl(flags.Brl, order.StockId) // 涨跌幅标识值 closingTime := SystemTimeGenerate(flags.StockMarketList, flags.BrlMarket, time.Now()) // 开盘时间 marketStatus, shareOrder, err := share.ShareBrlCacheDeal(ctx, userId, orderId, subKey, order, chg, priceNew, closingTime, blockTime) if err != nil || shareOrder == nil { applogger.Error("%v PlacingStockBrlOrders.ShareBrlCacheDeal:%v", common.ErrShareBrl, err) return flags.SetNull, err } // 计算保证金 = 订单价格 * 订单数量 / 杠杆 shareOrder.Order.MarketMoney = limitOrMarketPrice.Mul(decimal.RequireFromString(order.OrderNumber)).Div(pryNum).String() if !flags.CheckSetting { applogger.Debug("订单ID:%v", shareOrder.OrderId) applogger.Debug("订单交易对:%v", shareOrder.Symbol) applogger.Debug("订单状态:%v", shareOrder.Status) applogger.Debug("订单用户ID:%v", shareOrder.UserId) applogger.Debug("开盘价:%v", shareOrder.OpenPrice) applogger.Debug("收盘价:%v", shareOrder.ClosingPrice) applogger.Debug("下单信息:%v", shareOrder.Order) } // 6、股票订单(挂单|持仓)缓存列表,等待队列计算 if err = share.ShareBrlHashUserOrder(Reds, marketStatus, shareOrder); err != nil { applogger.Error("%v PlacingStockBrlOrders.ShareBrlHashUserOrder:%v", common.ErrShareBrl, err) return flags.SetNull, flags.ErrCacheDB } // 7、用户订阅股票订单信息 orderIdKey := virtual.OrderIdListKey(userKey, userId) if err = share.ShareBrlHashUserOrder(Reds, orderIdKey, shareOrder); err != nil { applogger.Error("%v PlacingStockBrlOrders.%v:%v", common.ErrShareBrl, userKey, err) return flags.SetNull, flags.ErrCacheDB } // 8、管理员订阅订单信息 if err = share.ShareBrlHashUserOrder(Reds, adminKey, shareOrder); err != nil { applogger.Error("%v PlacingStockBrlOrders.%v:%v", common.ErrShareBrl, adminKey, err) return flags.SetNull, flags.ErrCacheDB } return orderId, nil } // StockBrlOrderWriteDB // // @Description: 巴西股下单操作 // @receiver uo // @param ctx // @param userId // @param order // @return string // @return error func (uo *userOrderRepo) StockBrlOrderWriteDB(ctx context.Context, userId int64, order structure.ShareOrder, limitOrMarketPrice, lever decimal.Decimal) (string, error) { session := uo.data.mysqlDB.NewSession() defer session.Close() err := session.Begin() if err != nil { applogger.Error("%v StockBrlOrderWriteDB.Begin:%v", common.ErrShareBrl, err) return flags.SetNull, flags.ErrMySqlDB } // 获取当前下单用户的资产 var usableOld, frozenOld decimal.Decimal stockSgd, err := uo.GetBotUserStockBrlByUserIdAndStockId(session, userId, flags.ShareBrlBasicUnit) if err != nil || stockSgd == nil { applogger.Error("%v StockBrlOrderWriteDB.GetBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return flags.SetNull, flags.ErrMySqlDB } usableOld = decimal.RequireFromString(stockSgd.UsableNum) frozenOld = decimal.RequireFromString(stockSgd.FrozenNum) // 检查用户订单下单资产 if usableOld.IsZero() || usableOld.IsNegative() || frozenOld.IsNegative() { return flags.SetNull, flags.ErrShareOne } // 获取当前系统下单用户的非资产 var usableFOld, frozenFOld decimal.Decimal stockFSGD, err := uo.GetBotUserStockBrlByUserIdAndStockId(session, userId, order.StockId) if err != nil { applogger.Error("%v StockBrlOrderWriteDB.FeiSGD:%v", common.ErrShareBrl, err) return flags.SetNull, flags.ErrMySqlDB } if stockFSGD != nil { usableFOld = decimal.RequireFromString(stockFSGD.UsableNum) frozenFOld = decimal.RequireFromString(stockFSGD.FrozenNum) } if !flags.CheckSetting { applogger.Debug("下单可用资产:%v", usableOld) applogger.Debug("下单冻结资产:%v", frozenOld) applogger.Debug("下单查询非资产账户:%v", stockFSGD) applogger.Debug("下单可用非资产:%v", usableFOld) applogger.Debug("下单冻结非资产:%v", frozenFOld) } // 整理当前下单信息 serviceCost := decimal.RequireFromString(order.ServiceCost) // 订单手续费 orderNumber := decimal.RequireFromString(order.OrderNumber) // 订单数量 marketMoney := orderNumber.Mul(limitOrMarketPrice).Div(lever) // 订单金额(杠杆下单) = 订单数量 * 交易价格 / 杠杆 totalMoney := marketMoney.Add(serviceCost) // 订单总金额 order.MarketMoney = marketMoney.String() // 市值金额即为保证金 // 检查订单ID是否存在,新增下单信息 var orderId string if !CheckTypeStatus(order.Type) { orderId, err = uo.VerifyBotStockBrlTradeOrderId(session) if err != nil { applogger.Error("%v StockBrlOrderWriteDB.VerifyBotStockBrlTradeOrderId:%v", common.ErrShareBrl, err) return flags.SetNull, err } trade := orders.BotStockBrlTrade(ctx, userId, orderId, order) if err = uo.CreateBotStockBrlTrade(session, trade); err != nil { applogger.Error("%v StockBrlOrderWriteDB.CreateBotStockBrlTrade:%v", common.ErrShareBrl, err) return flags.SetNull, flags.ErrMySqlDB } } else { orderId, err = uo.VerifyBotStockBlockTradeOrderId(session) if err != nil { applogger.Error("%v StockBrlOrderWriteDB.VerifyBotStockBlockTradeOrderId:%v", common.ErrShareBrl, err) return flags.SetNull, err } trade := orders.BotStockBlockTrade(ctx, userId, orderId, order) if err = uo.CreateBotStockBlockTrade(session, trade); err != nil { applogger.Error("%v StockBrlOrderWriteDB.CreateBotStockBlockTrade:%v", common.ErrShareBrl, err) return flags.SetNull, flags.ErrMySqlDB } } // 下单判定 residue := usableOld.Sub(totalMoney).Div(usableOld) if usableOld.Cmp(totalMoney) <= 0 || residue.Cmp(utils.DecimalsStrInt()) <= 0 { return flags.SetNull, flags.ErrPublicTow } var usableNew, frozenNew, usableFNew, frozenFNew decimal.Decimal usableNew = usableOld.Sub(totalMoney) // 可用资产 frozenNew = frozenOld.Add(totalMoney) // 冻结资产 if order.StockId != flags.ShareBrlBasicUnit { usableFNew = usableFOld.Add(orderNumber) // 可用非资产 frozenFNew = frozenFOld // 冻结非资产 } // 检查用户订单下单资产 if usableNew.IsNegative() { return flags.SetNull, flags.ErrPublicTow } // 下单更新资产信息 stockSgdModel := orders.UpdateBotUserStockBrl(ctx, usableNew.String(), frozenNew.String()) err = uo.UpdateBotUserStockBrlByUserIdAndStockId(session, userId, flags.ShareBrlBasicUnit, stockSgdModel) if err != nil { applogger.Error("%v StockBrlOrderWriteDB.UpdateBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return flags.SetNull, flags.ErrMySqlDB } // 下单(新增|更新)非资产信息 if stockFSGD == nil { stockFTHBModel := orders.CreateBotUserStockBrl(ctx, userId, order.StockId, usableFNew.String(), frozenFNew.String()) err = uo.CreateBotUserStockBrlFTHB(session, stockFTHBModel) if err != nil { applogger.Error("%v StockBrlOrderWriteDB.CreateBotUserStockBrlFTHB:%v", common.ErrShareBrl, err) return flags.SetNull, flags.ErrMySqlDB } } else { stockFTHBModel := orders.UpdateBotUserStockBrl(ctx, usableFNew.String(), frozenFNew.String()) err = uo.UpdateBotUserStockBrlByUserIdAndStockId(session, userId, order.StockId, stockFTHBModel) if err != nil { applogger.Error("%v StockBrlOrderWriteDB.UpdateBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return flags.SetNull, flags.ErrMySqlDB } } if err = session.Commit(); err != nil { applogger.Error("%v StockBrlOrderWriteDB.Commit:%v", common.ErrShareBrl, err) return flags.SetNull, flags.ErrMySqlDB } return orderId, nil } // StockBrlOpenOrder // // @Description: 巴西股系统开仓 // @param ctx // @param db // @param userId // @param orderId // @param openPrice // @param order // @return error func StockBrlOpenOrder(ctx context.Context, db *xorm.EngineGroup, userId int64, orderId, openPrice string, order structure.ShareOrder) error { session := db.NewSession() defer session.Close() err := session.Begin() if err != nil { applogger.Error("%v StockBrlOpenOrder.NewSession:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } // 查询当前下单用户可用账户金额和冻结金额 var usable, frozen, usableNo, frozenNo decimal.Decimal stockThb, err := Uo.GetBotUserStockBrlByUserIdAndStockId(session, userId, flags.ShareBrlBasicUnit) if err != nil || stockThb == nil { applogger.Error("%v StockBrlOpenOrder.GetBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } usable = decimal.RequireFromString(stockThb.UsableNum) // 用户可用资产 frozen = decimal.RequireFromString(stockThb.FrozenNum) // 用户冻结资产 // 检查用户订单开仓资产 if usable.IsNegative() || frozen.IsNegative() { return flags.ErrPublicThree } if order.StockId != flags.ShareBrlBasicUnit { stockFThb, err := Uo.GetBotUserStockBrlByUserIdAndStockId(session, userId, order.StockId) if err != nil { applogger.Error("%v StockBrlOpenOrder.GetBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } usableNo = decimal.RequireFromString(stockFThb.UsableNum) // 用户非可用资产 frozenNo = decimal.RequireFromString(stockFThb.FrozenNum) // 用户非冻结资产 } if !flags.CheckSetting { applogger.Debug("下单可用金额:%v", usable) applogger.Debug("下单冻结金额:%v", frozen) applogger.Debug("下单非可用金额:%v", usableNo) applogger.Debug("下单非冻结金额:%v", frozenNo) } // 转换股票下单信息 orderNumber := decimal.RequireFromString(order.OrderNumber) // 下单股数 markerMoney := decimal.RequireFromString(order.MarketMoney) // 下单金额 serviceCost := decimal.RequireFromString(order.ServiceCost) // 下单手续费 totalMoney := markerMoney.Add(serviceCost) // 下单总金额 = (下单手续费 + 下单金额) openOrderPrice := decimal.RequireFromString(openPrice) // 开盘价格 if !flags.CheckSetting { applogger.Debug("下单订单数量:%v", orderNumber) applogger.Debug("下单订单金额:%v", markerMoney) applogger.Debug("下单订单手续费:%v", serviceCost) applogger.Debug("下单订单总金额:%v", totalMoney) } // 手续费记录 openPriceNew := openOrderPrice.Mul(orderNumber).String() // 开仓手续费 = 开仓价格 * 股数 * 开仓手续费 cost, err := Uo.CalculateHandlingFeesShare(ctx, session, int(userId), flags.ShareBrlMarketType, flags.OpenBrokType, orderId, openPriceNew) if err != nil { applogger.Error("%v StockBrlOpenOrder.CalculateHandlingFeesShare:%v", common.ErrShareBrl, err) return err } openServiceCost := decimal.RequireFromString(cost) // 开仓手续费 openMarkerMoney := openOrderPrice.Mul(orderNumber).Div(decimal.RequireFromString(order.PryNum)) // 开仓金额 = 开仓价格 * 股数 / 杠杆 openTotalMoney := openMarkerMoney.Add(openServiceCost) // 开仓总金额 = 开仓金额 + 开仓手续费 floatPrice := totalMoney.Sub(openTotalMoney) // 计算容差 = 下单总额 - 开仓总额 if !flags.CheckSetting { applogger.Debug("开仓订单价格:%v", openOrderPrice) applogger.Debug("开仓手续费:%v", openServiceCost) applogger.Debug("开仓总金额:%v", openTotalMoney) applogger.Debug("下单开仓总金额容差值:%v", floatPrice) } var usableNew, frozenNew, usableNoNew, frozenNoNew decimal.Decimal usableNew = usable.Add(floatPrice) // 可用资产(处理容差值) frozenNew = frozen.Sub(totalMoney).Add(openMarkerMoney) // 冻结资产(处理容差值)---> 当前冻结金额 = 原冻结金额 - 下单总额 if order.StockId != flags.ShareBrlBasicUnit { usableNoNew = usableNo // 非可用资产 frozenNoNew = frozenNo // 非冻结资产 } // 检查用户订单开仓资产 if frozenNew.IsNegative() || usableNew.IsNegative() { return flags.ErrPublicThree } if !flags.CheckSetting { applogger.Debug("下单后用户可用资产:%v", usableNew) applogger.Debug("下单后用户冻结资产:%v", frozenNew) } // 处理资产信息 userStockThb := orders.UpdateBotUserStockBrl(ctx, usableNew.String(), frozenNew.String()) if err = Uo.UpdateBotUserStockBrlByUserIdAndStockId(session, userId, flags.ShareBrlBasicUnit, userStockThb); err != nil { applogger.Error("%v StockBrlOpenOrder.UpdateBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } // 更新非资产信息 if order.StockId != flags.ShareBrlBasicUnit { userStockFThb := orders.UpdateBotUserStockBrl(ctx, usableNoNew.String(), frozenNoNew.String()) if err = Uo.UpdateBotUserStockBrlByUserIdAndStockId(session, userId, order.StockId, userStockFThb); err != nil { applogger.Error("%v StockBrlOpenOrder.UpdateBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } } // 返佣记录|资金信息|资金详情信息 if err = Uo.ShareBrlRebateCalculation(ctx, session, int(userId), flags.ShareBrlMarketType, flags.OpenBrokType, flags.OpenMRebate, cost, orderId, order.Type); err != nil { applogger.Error("%v StockBrlOpenOrder.ShareBrlRebateCalculation:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } // 处理订单信息(成交价|仓位|开仓时间|订单总金额|手续费|持仓状态) if !CheckTypeStatus(order.Type) { trade := orders.UpdateOpenBotStockBrlTrade(ctx, openPrice, orderNumber.String(), openTotalMoney.String(), openServiceCost.String(), openMarkerMoney.String()) if err = Uo.UpdateBotStockBrlTradeByOrderId(session, orderId, trade); err != nil { applogger.Error("%v StockBrlOpenOrder.UpdateBotStockBrlTradeByOrderId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } var list []models.BotUserStockBrlLog qData0 := orders.CreatBotUserStockBrlLog(ctx, userId, flags.CostMoney, flags.ShareBrlBasicUnit, NegativeValue(openServiceCost.String()), orderId) // 资金变动明细表(开仓手续费) qData1 := orders.CreatBotUserStockBrlLog(ctx, userId, flags.Freeze, flags.ShareBrlBasicUnit, NegativeValue(openMarkerMoney.String()), orderId) // 资金变动明细表(开仓保证金) qData2 := orders.CreatBotUserStockBrlLog(ctx, userId, flags.ChangeInto, order.StockId, orderNumber.String(), orderId) // 资金变动明细表(非资产) list = append(list, qData0, qData1, qData2) // 批量写入数据信息 if err = Uo.CreatBotUserStockBrlLogList(session, list); err != nil { applogger.Error("%v StockBrlOpenOrder.CreatBotUserStockBrlLogList:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } } else { trade := orders.UpdateOpenBotStockBlockTrade(ctx, openPrice, orderNumber.String(), openTotalMoney.String(), openServiceCost.String(), openMarkerMoney.String()) if err = Uo.UpdateBotStockBlockTradeByOrderId(session, orderId, trade); err != nil { applogger.Error("%v StockBrlOpenOrder.UpdateBotStockBlockTradeByOrderId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } var list []models.BotUserStockBlockLog qData0 := orders.CreatBotUserStockBlockLog(ctx, userId, flags.CostMoney, flags.ShareBrlBasicUnit, NegativeValue(openServiceCost.String()), orderId, order.Type) // 资金变动明细表(开仓手续费) qData1 := orders.CreatBotUserStockBlockLog(ctx, userId, flags.Freeze, flags.ShareBrlBasicUnit, NegativeValue(openMarkerMoney.String()), orderId, order.Type) // 资金变动明细表(开仓保证金) qData2 := orders.CreatBotUserStockBlockLog(ctx, userId, flags.ChangeInto, order.StockId, orderNumber.String(), orderId, order.Type) // 资金变动明细表(非资产) list = append(list, qData0, qData1, qData2) // 批量写入数据信息 if err = Uo.CreatBotUserStockBlockLogList(session, list); err != nil { applogger.Error("%v StockBrlOpenOrder.CreatBotUserStockBlockLogList:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } } if err = session.Commit(); err != nil { applogger.Error("%v StockBrlOpenOrder.Commit:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } return nil } // StockBrlClosingOrder // // @Description: 巴西股系统平仓 // @param ctx // @param db // @param orderId // @param price // @param order // @return error func StockBrlClosingOrder(ctx context.Context, db *xorm.EngineGroup, orderId string, price string, order structure.ShareOrder) error { session := db.NewSession() defer session.Close() err := session.Begin() if err != nil { applogger.Error("%v StockBrlClosingOrder.NewSession:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } // 查询订单信息 var userId int64 var dealPrice, orderNumber, totalAmount, serviceCost, markerMoney decimal.Decimal if !CheckTypeStatus(order.Type) { tread, err := Uo.GetBotStockBrlTradeByOrderIdOrStatus(session, orderId, flags.PositionStatus) if err != nil || tread == nil { applogger.Error("%v StockBrlClosingOrder.GetBotStockBrlTradeByOrderIdOrStatus:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } userId = int64(tread.UserId) // 用户Id orderNumber = decimal.RequireFromString(tread.OrderNumber) // 下单数量 dealPrice = decimal.RequireFromString(tread.DealPrice) // 开仓价格 totalAmount = decimal.RequireFromString(tread.OrderMoney) // 开仓总金额 serviceCost = decimal.RequireFromString(tread.ServiceCost) // 开仓手续费 markerMoney = decimal.RequireFromString(tread.MarketMoney) // 开仓下单金额 } else { tread, err := Uo.GetBotStockBlockTradeByOrderIdOrStatus(session, orderId, flags.PositionStatus) if err != nil || tread == nil { applogger.Error("%v StockBrlClosingOrder.GetBotStockBlockTradeByOrderIdOrStatus:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } userId = int64(tread.UserId) // 用户Id orderNumber = decimal.RequireFromString(tread.OrderNumber) // 下单数量 dealPrice = decimal.RequireFromString(tread.DealPrice) // 开仓价格 totalAmount = decimal.RequireFromString(tread.OrderMoney) // 开仓总金额 serviceCost = decimal.RequireFromString(tread.ServiceCost) // 开仓手续费 markerMoney = decimal.RequireFromString(tread.MarketMoney) // 开仓下单金额 } if !flags.CheckSetting { applogger.Debug("下单开仓用户Id:%v", userId) applogger.Debug("下单开仓开仓价格:%v", dealPrice) applogger.Debug("下单开仓订单数量:%v", orderNumber) applogger.Debug("下单开仓总金额:%v", totalAmount) applogger.Debug("下单开仓手续费:%v", serviceCost) applogger.Debug("下单开仓开仓金额:%v", markerMoney) } // 查询当前下单用户可用账户金额和冻结金额 var usable, frozen, usableNo, frozenNo decimal.Decimal userStockThb, err := Uo.GetBotUserStockBrlByUserIdAndStockId(session, userId, flags.ShareBrlBasicUnit) if err != nil { applogger.Error("%v StockBrlClosingOrder.GetBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } usable = decimal.RequireFromString(userStockThb.UsableNum) // 用户可用资金 frozen = decimal.RequireFromString(userStockThb.FrozenNum) // 用户非冻结资金 // 检查用户订单平仓资产 if usable.IsNegative() || frozen.IsNegative() { return flags.ErrShareTow } // 查询当前下单用户可用非账户和冻结金额 if order.StockId != flags.ShareBrlBasicUnit { userStockFThb, err := Uo.GetBotUserStockBrlByUserIdAndStockId(session, userId, order.StockId) if err != nil { applogger.Error("%v StockBrlClosingOrder.GetBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } usableNo = decimal.RequireFromString(userStockFThb.UsableNum) // 用户非可用资金 frozenNo = decimal.RequireFromString(userStockFThb.FrozenNum) // 用户非冻结资金 } if !flags.CheckSetting { applogger.Debug("下单可用金额:%v", usable) applogger.Debug("下单冻结金额:%v", frozen) applogger.Debug("下单非可用金额:%v", usableNo) applogger.Debug("下单非冻结金额:%v", frozenNo) } // 手续费处理 closePrice := decimal.RequireFromString(price) // 平仓价格 cloePriceCost := closePrice.Mul(orderNumber).String() // 平仓手续费 = 平仓价格 * 股数 * 手续费比例 cost, err := Uo.CalculateHandlingFeesShare(ctx, session, int(userId), flags.ShareBrlMarketType, flags.ClosingBrokType, orderId, cloePriceCost) if err != nil { applogger.Error("%v StockBrlClosingOrder.CalculateHandlingFeesShare:%v", common.ErrShareBrl, err) return err } closeServiceCost := decimal.RequireFromString(cost) if !flags.CheckSetting { applogger.Debug("平仓价格:%v", closePrice) applogger.Debug("平仓手续费手续费:%v", closeServiceCost) } //已经实现盈亏计算公式(已平仓结算方式) //买涨 已经实现盈亏 = (平仓成交价-开仓成交价)*股数 //买跌 已经实现盈亏 = (开仓成交价-平仓成交价)*股数 var usableNew, frozenNew, usableNewNo, frozenNewNo, subPrice, resultPrice decimal.Decimal switch order.TradeType { case flags.TradeTypeBuy: // 买涨 subPrice = closePrice.Sub(dealPrice) resultPrice = subPrice.Mul(orderNumber) case flags.TradeTypeSell: // 买跌 subPrice = dealPrice.Sub(closePrice) resultPrice = subPrice.Mul(orderNumber) default: } // 判定亏损不能超过 = 保证金 + 平仓手续费 if resultPrice.IsNegative() { amountLoss := markerMoney.Sub(closeServiceCost) if resultPrice.Abs().Cmp(amountLoss) >= 0 { resultPrice = amountLoss.Neg() } } // 用户资产账户 usableNew = usable.Add(resultPrice).Sub(closeServiceCost).Add(markerMoney) // 可用资产 = 原可用资产 + ((正负)盈亏) - 平仓手续费 + 开仓下单金额 if frozen.Cmp(markerMoney) == -1 { frozenNew = frozen.Sub(frozen) // 冻结资产 } else { frozenNew = frozen.Sub(markerMoney) // 冻结资产 } // 用户非资产账户 if order.StockId != flags.ShareBrlBasicUnit { usableNewNo = usableNo.Sub(orderNumber) // 可用非资产 = 原可用非资产 - 下单股数 frozenNewNo = frozenNo // 可用非冻结资产 } // 检查用户订单平仓资产 if frozenNew.IsNegative() || usableNewNo.IsNegative() { return flags.ErrShareTow } if !flags.CheckSetting { applogger.Debug("可用资产:%v", usableNew) applogger.Debug("冻结资产:%v", frozenNew) applogger.Debug("可用非资产:%v", usableNewNo) applogger.Debug("冻结非资产:%v", frozenNewNo) } // 平仓(处理资产表(资产)) userStockUTHB := orders.UpdateBotUserStockBrl(ctx, usableNew.String(), frozenNew.String()) if err = Uo.UpdateBotUserStockBrlByUserIdAndStockId(session, userId, flags.ShareBrlBasicUnit, userStockUTHB); err != nil { applogger.Error("%v StockBrlClosingOrder.UpdateBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } // 平仓(处理资产表(非资产)) if order.StockId != flags.ShareBrlBasicUnit { userStockFTHB := orders.UpdateBotUserStockBrl(ctx, usableNewNo.String(), frozenNewNo.String()) if err = Uo.UpdateBotUserStockBrlByUserIdAndStockId(session, userId, order.StockId, userStockFTHB); err != nil { applogger.Error("%v StockBrlClosingOrder..UpdateBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } } // 平仓(返佣记录表|资产表|资金变动表) if err = Uo.ShareBrlRebateCalculation(ctx, session, int(userId), flags.ShareBrlMarketType, flags.ClosingBrokType, flags.CloseMRebate, cost, orderId, order.Type); err != nil { applogger.Error("%v StockBrlClosingOrder.ShareBrlRebateCalculation:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } // 平仓(处理订单信息(平仓价|保证金|平仓|订单总金额|平仓手续费|完成订单)) if !CheckTypeStatus(order.Type) { trade := orders.UpdateCloseBotStockBrlTrade(ctx, price, cost) if err = Uo.UpdateBotStockBrlTradeByOrderId(session, orderId, trade); err != nil { applogger.Error("%v StockBrlClosingOrder.UpdateBotStockBrlTradeByOrderId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } var list []models.BotUserStockBrlLog qData0 := orders.CreatBotUserStockBrlLog(ctx, userId, flags.Thaw, flags.ShareBrlBasicUnit, markerMoney.String(), orderId) // 平仓(资金变动明细表(开仓保证金)) qData1 := orders.CreatBotUserStockBrlLog(ctx, userId, flags.CostMoney, flags.ShareBrlBasicUnit, NegativeValue(closeServiceCost.String()), orderId) // 平仓(资金变动明细表(-平仓手续费)) qData2 := orders.CreatBotUserStockBrlLog(ctx, userId, flags.TransferOut, order.StockId, NegativeValue(orderNumber.String()), orderId) // 平仓(资金变动明细表(-非资产)) list = append(list, qData0, qData1, qData2) // 平仓(资金变动明细表(正负盈亏) if resultPrice.IsNegative() { qData3 := orders.CreatBotUserStockBrlLog(ctx, userId, flags.TransferOut, flags.ShareBrlBasicUnit, resultPrice.String(), orderId) list = append(list, qData3) } else { qData4 := orders.CreatBotUserStockBrlLog(ctx, userId, flags.ChangeInto, flags.ShareBrlBasicUnit, resultPrice.String(), orderId) list = append(list, qData4) } // 平仓(批量写入交易订单日志信息) if err = Uo.CreatBotUserStockBrlLogList(session, list); err != nil { applogger.Error("%v StockBrlClosingOrder.CreatBotUserStockBrlLogList:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } } else { trade := orders.UpdateCloseBotStockBlockTrade(ctx, price, cost) if err = Uo.UpdateBotStockBlockTradeByOrderId(session, orderId, trade); err != nil { applogger.Error("%v StockBrlClosingOrder.UpdateBotStockBlockTradeByOrderId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } var list []models.BotUserStockBlockLog qData0 := orders.CreatBotUserStockBlockLog(ctx, userId, flags.Thaw, flags.ShareBrlBasicUnit, markerMoney.String(), orderId, order.Type) // 平仓(资金变动明细表(开仓保证金)) qData1 := orders.CreatBotUserStockBlockLog(ctx, userId, flags.CostMoney, flags.ShareBrlBasicUnit, NegativeValue(closeServiceCost.String()), orderId, order.Type) // 平仓(资金变动明细表(-平仓手续费)) qData2 := orders.CreatBotUserStockBlockLog(ctx, userId, flags.TransferOut, order.StockId, NegativeValue(orderNumber.String()), orderId, order.Type) // 平仓(资金变动明细表(-非资产)) list = append(list, qData0, qData1, qData2) // 平仓(资金变动明细表(正负盈亏) if resultPrice.IsNegative() { qData3 := orders.CreatBotUserStockBlockLog(ctx, userId, flags.TransferOut, flags.ShareBrlBasicUnit, resultPrice.String(), orderId, order.Type) list = append(list, qData3) } else { qData4 := orders.CreatBotUserStockBlockLog(ctx, userId, flags.ChangeInto, flags.ShareBrlBasicUnit, resultPrice.String(), orderId, order.Type) list = append(list, qData4) } // 平仓(批量写入交易订单日志信息) if err = Uo.CreatBotUserStockBlockLogList(session, list); err != nil { applogger.Error("%v StockBrlClosingOrder.CreatBotUserStockBlockLogList:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } } if err = session.Commit(); err != nil { applogger.Error("%v StockBrlClosingOrder.Commit:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } return nil } // UpdateBotStockBrlCancelByOrderId // // @Description: 巴西股撤单 // @receiver uo // @param ctx // @param orderId // @return bool // @return error func (uo *userOrderRepo) UpdateBotStockBrlCancelByOrderId(ctx context.Context, orderId string, typeStatus int64) (bool, error) { session := uo.data.mysqlDB.NewSession() defer session.Close() err := session.Begin() if err != nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.Begin:%v", common.ErrShareBrl, err) return false, flags.ErrMySqlDB } // 获取订单信息 var userId int64 var stockId string var marketMoneyOld, serviceCostOld, orderNumber decimal.Decimal if !CheckTypeStatus(typeStatus) { stockTrade, err := uo.GetBotStockBrlTradeByOrderId(session, orderId) if err != nil || stockTrade == nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.GetBotStockBrlTradeByOrderId:%v", common.ErrShareBrl, err) return false, flags.ErrMySqlDB } marketMoneyOld = decimal.RequireFromString(stockTrade.MarketMoney) // 订单Id serviceCostOld = decimal.RequireFromString(stockTrade.ServiceCost) // 手续费 orderNumber = decimal.RequireFromString(stockTrade.OrderNumber) // 订单数量 userId = int64(stockTrade.UserId) // 用户Id stockId = stockTrade.StockId // 下单交易对 } else { stockTrade, err := uo.GetBotStockBlockTradeByOrderId(session, orderId) if err != nil || stockTrade == nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.GetBotStockBlockTradeByOrderId:%v", common.ErrShareBrl, err) return false, flags.ErrMySqlDB } marketMoneyOld = decimal.RequireFromString(stockTrade.MarketMoney) // 订单Id serviceCostOld = decimal.RequireFromString(stockTrade.ServiceCost) // 手续费 orderNumber = decimal.RequireFromString(stockTrade.OrderNumber) // 订单数量 userId = int64(stockTrade.UserId) // 用户Id stockId = stockTrade.StockId // 下单交易对 } // 用户资产信息 var usable, frozen, usableNo, frozenNo decimal.Decimal stockThb, err := uo.GetBotUserStockBrlByUserIdAndStockId(session, userId, flags.ShareBrlBasicUnit) if err != nil || stockThb == nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.GetBotUserStockSgdByUserIdAndStockId:%v", common.ErrShareBrl, err) return false, flags.ErrMySqlDB } usable = decimal.RequireFromString(stockThb.UsableNum) // 用户账户可用资产 frozen = decimal.RequireFromString(stockThb.FrozenNum) // 用户账户冻结资产 // 检查用户订单撤单资产 if usable.IsNegative() || frozen.IsNegative() { return false, flags.ErrShareNine } if stockId != flags.ShareBrlBasicUnit { stockFThb, err := uo.GetBotUserStockBrlByUserIdAndStockId(session, userId, stockId) if err != nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.GetBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return false, flags.ErrPublicFour } usableNo = decimal.RequireFromString(stockFThb.UsableNum) // 用户非账户可用资产 frozenNo = decimal.RequireFromString(stockFThb.FrozenNum) // 用户非账户冻结资产 } if !flags.CheckSetting { applogger.Debug("用户原始可用资金:%v", usable) applogger.Debug("用户原始冻结资金:%v", frozen) applogger.Debug("用户原始可用非资金:%v", usableNo) applogger.Debug("用户原始冻结非资金:%v", frozenNo) } // 更新订单信息 var entrustKey, userKey, adminKey string if !CheckTypeStatus(typeStatus) { botStockTrade := orders.BotStockBrlCancelByOrderId(ctx) if err = uo.UpdateBotStockBrlTradeByOrderId(session, orderId, botStockTrade); err != nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.UpdateBotStockBrlTradeByOrderId:%v", common.ErrShareBrl, err) return false, flags.ErrMySqlDB } // 缓存Key entrustKey = setting.MarketShareBrlEntrust userKey = setting.ShareBrlSubscribe adminKey = setting.AdminShareBrlSubscribe } else { botStockTrade := orders.BotStockBlockCancelByOrderId(ctx) if err = uo.UpdateBotStockBlockTradeByOrderId(session, orderId, botStockTrade); err != nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.UpdateBotStockBlockTradeByOrderId:%v", common.ErrShareBrl, err) return false, flags.ErrMySqlDB } // 缓存Key entrustKey = setting.MarketShareBlkEntrust userKey = setting.ShareBlkSubscribe adminKey = setting.AdminShareBlkSubscribe } // Operational Spot Asset Table totalMoney := marketMoneyOld.Add(serviceCostOld) // 订单总金额 // update total asset data var usableNew, frozenNew, usableNoNew, frozenNoNew decimal.Decimal usableNew = usable.Add(totalMoney) // 用户总资产 frozenNew = frozen.Sub(totalMoney) // 用户冻结资产 if stockId != flags.ShareBrlBasicUnit { usableNoNew = usableNo.Sub(orderNumber) // 用户非可用资产 frozenNoNew = frozenNo // 用户非冻结资产 } // 检查用户订单撤单资产 if frozenNew.IsNegative() || usableNoNew.IsNegative() { return false, flags.ErrShareNine } if !flags.CheckSetting { applogger.Debug("用户撤单可用总资产:%v", usableNew) applogger.Debug("用户撤单冻结总资产:%v", frozenNew) applogger.Debug("用户非撤单可用总资产:%v", usableNoNew) applogger.Debug("用户非撤单冻结总资产:%v", frozenNoNew) } // 更新资产信息和非资产信息 userStockTHB := orders.UpdateBotUserStockBrl(ctx, usableNew.String(), frozenNew.String()) if err = uo.UpdateBotUserStockBrlByUserIdAndStockId(session, userId, flags.ShareBrlBasicUnit, userStockTHB); err != nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.SGD.UpdateBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return false, flags.ErrMySqlDB } if stockId != flags.ShareBrlBasicUnit { userStockFTHB := orders.UpdateBotUserStockBrl(ctx, usableNoNew.String(), frozenNoNew.String()) if err = uo.UpdateBotUserStockBrlByUserIdAndStockId(session, userId, stockId, userStockFTHB); err != nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.UpdateBotUserStockBrlByUserIdAndStockId:%v", common.ErrShareBrl, err) return false, flags.ErrMySqlDB } } // 删除订单缓存列表 if err = Reds.HDel(context.Background(), entrustKey, orderId).Err(); err != nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.HDel:%v", common.ErrShareBrl, err) return false, flags.ErrCacheDB } // 更新用户订阅订单缓存列表 userSubKey := virtual.OrderIdListKey(userKey, userId) if err = share.UpdateShareBrlHashByOrderId(Reds, orderId, userSubKey, flags.Cancel); err != nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.%v:%v", common.ErrShareBrl, userKey, err) return false, flags.ErrCacheDB } // 更新管理员订阅订单缓存列表 if err = UpdateShareBrlSubscribeHashStatusByOrderId(orderId, adminKey, flags.Cancel, flags.SetNull); err != nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.%v:%v", common.ErrShareBrl, adminKey, err) return false, flags.ErrCacheDB } if err = session.Commit(); err != nil { applogger.Error("%v UpdateBotStockBrlCancelByOrderId.Commit:%v", common.ErrShareSgd, err) return false, flags.ErrMySqlDB } return true, nil } // UpdateBotStockBrlStopByOrderId // // @Description: 巴西股设置止盈止损 // @receiver uo // @param ctx // @param order // @return bool // @return error func (uo *userOrderRepo) UpdateBotStockBrlStopByOrderId(ctx context.Context, order structure.StopOrder) (bool, error) { session := uo.data.mysqlDB.NewSession() defer session.Close() err := session.Begin() if err != nil { applogger.Error("%v UpdateBotStockBrlStopByOrderId.NewSession:%v", common.ErrShareBrl, err) return false, flags.ErrMySqlDB } // 设置止盈止损 var userId int64 if order.StopType == 1 { // 下单信息 checkBool, stopWinPrice, stopLossPrice, err := uo.UpdateVoteStopType(order) if err != nil { applogger.Error("%v UpdateBotStockBrlStopByOrderId.UpdateVoteStopType:%v", common.ErrShareBrl, err) return false, err } if !flags.CheckSetting { applogger.Debug("当前止盈止损数据:%v,%v,%v", checkBool, stopWinPrice, stopLossPrice) } // 止盈止损判定 var tradeType int var limitOrMarketPrice decimal.Decimal if !CheckTypeStatus(order.Type) { trade, err := uo.GetBotStockBrlTradeByOrderIdOrStatus(session, order.OrderId, flags.PositionStatus) if err != nil || trade == nil { applogger.Error("%v UpdateBotStockBrlStopByOrderId.GetBotStockBrlTradeByOrderIdOrStatus:%v", common.ErrShareBrl, err) return false, flags.ErrShareFour } tradeType = trade.TradeType userId = int64(trade.UserId) // 下单判定设置(限价|市价|开仓价) limitOrMarketPrice, err = uo.UpdateShareBrlVoteDealType(trade) if err != nil { applogger.Error("%v UpdateBotStockBrlStopByOrderId.UpdateShareBrlVoteDealType:%v", common.ErrShareBrl, err) return false, err } } else { trade, err := uo.GetBotStockBlockTradeByOrderIdOrStatus(session, order.OrderId, flags.PositionStatus) if err != nil || trade == nil { applogger.Error("%v UpdateBotStockBrlStopByOrderId.GetBotStockBlockTradeByOrderIdOrStatus:%v", common.ErrShareBrl, err) return false, flags.ErrShareFour } tradeType = trade.TradeType userId = int64(trade.UserId) // 下单判定设置(限价|市价|开仓价) limitOrMarketPrice, err = uo.UpdateShareBlockVoteDealType(trade) if err != nil { applogger.Error("%v UpdateBotStockBrlStopByOrderId.UpdateShareBlockVoteDealType:%v", common.ErrShareBrl, err) return false, err } } if !flags.CheckSetting { applogger.Debug("当前开仓价格:%v", limitOrMarketPrice) } // 下单判定设置(买涨|买跌) if err = uo.VoteTradeType(int64(tradeType), stopWinPrice, stopLossPrice, limitOrMarketPrice, checkBool); err != nil { applogger.Error("%v UpdateBotStockBrlStopByOrderId.VoteTradeType:%v", common.ErrShareBrl, err) return false, err } } else { order.StopLossPrice = decimal.Zero.String() order.StopWinPrice = decimal.Zero.String() } // TODO: 获取存在IPO未支付订单的用户 userIdMap, _ := GetBotUserArrears(ctx) _, ok := userIdMap[userId] if ok { return false, flags.ErrPublicServe } // 更新订单表 var positionKey string if !CheckTypeStatus(order.Type) { botStockTrade := orders.BotStockBrlStopByOrderId(ctx, order) if err = uo.UpdateBotStockBrlTradeByOrderId(session, order.OrderId, botStockTrade); err != nil { applogger.Error("%v UpdateBotStockBrlStopByOrderId.UpdateBotStockBrlTradeByOrderId:%v", common.ErrShareBrl, err) return false, flags.ErrMySqlDB } positionKey = setting.MarketShareBrlPosition } else { botStockTrade := orders.BotStockBlockStopByOrderId(ctx, order) if err = uo.UpdateBotStockBlockTradeByOrderId(session, order.OrderId, botStockTrade); err != nil { applogger.Error("%v UpdateBotStockBrlStopByOrderId.UpdateBotStockBlockTradeByOrderId:%v", common.ErrShareBrl, err) return false, flags.ErrMySqlDB } positionKey = setting.MarketShareBlkPosition } // 挂单缓存队列 if err = share.UpdateShareBrlStopByOrderId(Reds, order, positionKey, flags.Position); err != nil { applogger.Error("%v UpdateBotStockBrlStopByOrderId.UpdateShareBrlStopByOrderId:%v", common.ErrShareBrl, err) return false, flags.ErrCacheDB } if err = session.Commit(); err != nil { applogger.Error("%v UpdateBotStockBrlStopByOrderId.Commit:%v", common.ErrShareBrl, err) return false, flags.ErrMySqlDB } return true, nil } // UpdateBotStockBrlClosingByOrderId // // @Description: 巴西股用户平仓 // @receiver uo // @param ctx // @param orderId // @return bool // @return error func (uo *userOrderRepo) UpdateBotStockBrlClosingByOrderId(ctx context.Context, orderId string, typeStatus int64) (bool, error) { // 下单判定-冷静期停止所有交易 if CheckGlobalTread(flags.BrlMarket) { return false, flags.ErrStopTread } // 1、查询持仓缓存列表数据并清理对应缓存 var positionKey, userKey, adminKey string if !CheckTypeStatus(typeStatus) { positionKey = setting.MarketShareBrlPosition userKey = setting.ShareBrlSubscribe adminKey = setting.AdminShareBrlSubscribe } else { positionKey = setting.MarketShareBlkPosition userKey = setting.ShareBlkSubscribe adminKey = setting.AdminShareBlkSubscribe } var entrustCache *share.ShareBrlTallyCache entrust, err := Reds.HGet(context.Background(), positionKey, orderId).Result() if err != nil { applogger.Error("%v UpdateBotStockBrlClosingByOrderId.HGet:%v", common.ErrShareBrl, err) return false, flags.ErrShareFive } var entrustJson share.ShareBrlTallyCache if err = json.Unmarshal([]byte(entrust), &entrustJson); err != nil { applogger.Error("%v UpdateBotStockBrlClosingByOrderId.Unmarshal:%v", common.ErrShareBrl, err) return false, flags.ErrCacheDB } if orderId == entrustJson.OrderId { entrustCache = &entrustJson } // 2、判定是否存在平仓订单 if entrustCache == nil { return false, flags.ErrShareFive } // TODO: 获取存在IPO未支付订单的用户 userIdMap, _ := GetBotUserArrears(ctx) _, ok := userIdMap[entrustJson.UserId] if ok { return false, flags.ErrPublicServe } // 市场设置交易时间(T+0,T+1,T+2s......) if !CheckShareSystemTime(entrustCache.ClosingTime) { return false, flags.ErrStopTread } if !flags.CheckSetting { applogger.Debug("手动平仓:%v", entrustCache) } // 3、当前最新价格 var closingPrice decimal.Decimal subKey := publicData.SymbolCache(flags.Brl, entrustCache.Symbol, flags.TradeTypePrice) closingPrice, err = uo.GetShareBrlTheLatestPrice(subKey, entrustCache.Order.TradeType) if err != nil { applogger.Error("%v UpdateBotStockBrlClosingByOrderId.GetShareBrlTheLatestPrice:%v", common.ErrShareBrl, err) return false, flags.ErrStopTread } // 4、平仓处理 if err = StockBrlClosingOrder(ctx, Msql, orderId, closingPrice.String(), entrustCache.Order); err != nil { applogger.Error("%v UpdateBotStockBrlClosingByOrderId.StockBrlClosingOrder:%v", common.ErrShareBrl, err) return false, err } // 5、清理持仓订单信息 var removedCount int64 removedCount, err = Reds.HDel(context.Background(), positionKey, orderId).Result() if err != nil || removedCount == 0 { applogger.Error("%v UpdateBotStockBrlClosingByOrderId.HDel:%v", common.ErrShareBrl, err) return false, flags.ErrCacheDB } // 6、平仓更新订阅缓存订单状态 userSubKey := virtual.OrderIdListKey(userKey, entrustCache.UserId) if err = UpdateShareBrlSubscribeHashStatusByOrderId(orderId, userSubKey, flags.Close, flags.SetNull); err != nil { applogger.Error("%v UpdateBotStockBrlClosingByOrderId.%v:%v", common.ErrShareBrl, userKey, err) return false, flags.ErrCacheDB } // 7、平仓更新管理员订阅缓存订单状态 if err = UpdateShareBrlSubscribeHashStatusByOrderId(orderId, adminKey, flags.Close, flags.SetNull); err != nil { applogger.Error("%v UpdateBotStockBrlClosingByOrderId.%v:%v", common.ErrShareBrl, adminKey, err) return false, flags.ErrCacheDB } return true, nil } // UpdateBotStockBrlAllClosingByOrderId // // @Description: 巴西股用户一键平仓 // @receiver uo // @param ctx // @param userId // @return error func (uo *userOrderRepo) UpdateBotStockBrlAllClosingByOrderId(ctx context.Context, userId int64) error { // 下单判定-冷静期停止所有交易 if CheckGlobalTread(flags.BrlMarket) { return flags.ErrStopTread } // TODO: 获取存在IPO未支付订单的用户 userIdMap, _ := GetBotUserArrears(ctx) _, isOk := userIdMap[userId] if isOk { return flags.ErrPublicServe } // 1、查询当前用户所有订单 orderMap, err := uo.GetBotStockBrlTradeByUserId(userId) if err != nil { applogger.Error("%v UpdateBotStockBrlAllClosingByOrderId.GetBotStockBrlTradeByUserId:%v", common.ErrShareBrl, err) return flags.ErrMySqlDB } // 2、查询持仓缓存列表数据-1、清理持仓列表缓存 2、处理平仓数据 3、清理订单ID缓存列表 entrust, err := Reds.HGetAll(context.Background(), setting.MarketShareBrlPosition).Result() if err != nil { applogger.Error("%v UpdateBotStockBrlAllClosingByOrderId.HGetAll:%v", common.ErrShareBrl, err) return flags.ErrShareFive } // 3、循环检查股票交易对最新价格(有一个查询不到既不能平仓) var entrustList []share.ShareBrlTallyCache closePriceMap := make(map[string]decimal.Decimal) for key, value := range entrust { var entrustJson share.ShareBrlTallyCache if err = json.Unmarshal([]byte(value), &entrustJson); err != nil { applogger.Error("%v UpdateBotStockBrlAllClosingByOrderId.Unmarshal:%v", common.ErrShareBrl, err) return flags.ErrStopTread } _, ok := orderMap[entrustJson.OrderId] if ok { var closingPrice decimal.Decimal subKey := publicData.SymbolCache(flags.Brl, entrustJson.Symbol, flags.TradeTypePrice) closingPrice, err = uo.GetShareBrlTheLatestPrice(subKey, entrustJson.Order.TradeType) if err != nil { applogger.Error("%v UpdateBotStockBrlAllClosingByOrderId.GetShareSgdTheLatestPrice:%v", common.ErrShareBrl, err) return flags.ErrStopTread } if !flags.CheckSetting { applogger.Debug("订阅Key:%v,最新价格:%v,订单ID:%v", subKey, closingPrice, entrustJson.OrderId) } closePriceMap[key] = closingPrice entrustList = append(entrustList, entrustJson) } } // 4、股票一键平仓 for _, value := range entrustList { closePrice, ok := closePriceMap[value.OrderId] if ok { // 平仓 if err = StockBrlClosingOrder(ctx, uo.data.mysqlDB, value.OrderId, closePrice.String(), value.Order); err != nil { applogger.Error("%v UpdateBotStockBrlAllClosingByOrderId.StockBrlClosingOrder:%v", common.ErrShareBrl, err) return err } // 清理持仓缓存列表 var removedCount int64 removedCount, err = Reds.HDel(context.Background(), setting.MarketShareBrlPosition, value.OrderId).Result() if err != nil || removedCount == 0 { applogger.Error("%v UpdateBotStockBrlAllClosingByOrderId.HDel:%v", common.ErrShareBrl, err) return flags.ErrCacheDB } // 平仓更新用户订阅订单状态 userSubKey := virtual.OrderIdListKey(setting.ShareBrlSubscribe, value.UserId) if err = UpdateShareBrlSubscribeHashStatusByOrderId(value.OrderId, userSubKey, flags.Close, flags.SetNull); err != nil { applogger.Error("%v UpdateBotStockBrlAllClosingByOrderId.ShareBrlSubscribe:%v", common.ErrShareBrl, err) return flags.ErrCacheDB } // 平仓更新管理员订阅订单状态 if err = UpdateShareBrlSubscribeHashStatusByOrderId(value.OrderId, setting.AdminShareBrlSubscribe, flags.Close, flags.SetNull); err != nil { applogger.Error("%v UpdateBotStockBrlAllClosingByOrderId.AdminShareBrlSubscribe:%v", common.ErrShareBrl, err) return flags.ErrCacheDB } } } return nil } // GetBotStockBrlTradeByUserId // // @Description: // @receiver uo // @param ctx // @param userId // @return map[string]string // @return error func (uo *userOrderRepo) GetBotStockBrlTradeByUserId(userId int64) (map[string]string, error) { var botStockBrlTrade []models.BotStockBrlTrade if err := uo.data.mysqlDB.Table(flags.BotStockBrlTrade). Where("user_id = ?", userId). Where("status = 1"). Find(&botStockBrlTrade); err != nil { return nil, err } botMap := make(map[string]string) for _, value := range botStockBrlTrade { botMap[value.OrderId] = value.OrderId } return botMap, nil } // GetShareBrlTheLatestPrice // // @Description: // @receiver uo // @param ctx // @param subKey // @param tradeType // @return decimal.Decimal // @return error func (uo *userOrderRepo) GetShareBrlTheLatestPrice(subKey string, tradeType int64) (decimal.Decimal, error) { priceNew, err := share.ShareBrlSubMarketPrice(subKey) if err != nil { applogger.Error("%v GetShareBrlTheLatestPrice.ShareBrlSubMarketPrice:%v", common.ErrShareBrl, err) return decimal.Decimal{}, err } priceS := decimal.RequireFromString(priceNew) var openPrice decimal.Decimal difference := priceS.Mul(utils.Difference()) // 设置价差 switch tradeType { case flags.TradeTypeBuy: // 买涨 openPrice = priceS.Sub(difference) // 开仓价格 case flags.TradeTypeSell: // 买跌 openPrice = priceS.Add(difference) // 开仓价格 default: } return openPrice, nil } // GetBotStockBrlTradeByOrderId // // @Description: // @receiver uo // @param ctx // @param session // @param orderId // @return *models.BotStockBrlTrade // @return error func (uo *userOrderRepo) GetBotStockBrlTradeByOrderId(session *xorm.Session, orderId string) (*models.BotStockBrlTrade, error) { var botStockBrlTrade []models.BotStockBrlTrade if err := session.Table(flags.BotStockBrlTrade). Where("order_id = ?", orderId). Find(&botStockBrlTrade); err != nil { return nil, err } for _, value := range botStockBrlTrade { return &value, nil } return nil, nil } // GetBotUserStockBrlByUserIdAndStockId // // @Description: // @receiver uo // @param ctx // @param session // @param userId // @param stockId // @return *models.BotUserStockBrl // @return error func (uo *userOrderRepo) GetBotUserStockBrlByUserIdAndStockId(session *xorm.Session, userId int64, stockId string) (*models.BotUserStockBrl, error) { var stockBrl []models.BotUserStockBrl if err := session.Table(flags.BotUserStockBrl). Where("user_id = ?", userId). Where("stock_id = ?", stockId). Find(&stockBrl); err != nil || len(stockBrl) <= 0 { return nil, err } for _, value := range stockBrl { return &value, nil } return nil, nil } // UpdateBotStockBrlTradeByOrderId // // @Description: // @receiver uo // @param ctx // @param session // @param orderId // @param stock // @return error func (uo *userOrderRepo) UpdateBotStockBrlTradeByOrderId(session *xorm.Session, orderId string, stock models.BotStockBrlTrade) error { _, err := session.Table(flags.BotStockBrlTrade). Where("order_id = ?", orderId). Update(&stock) if err != nil { return err } return nil } // CreateBotStockBrlTrade // // @Description: // @receiver uo // @param ctx // @param session // @param trade // @return error func (uo *userOrderRepo) CreateBotStockBrlTrade(session *xorm.Session, trade models.BotStockBrlTrade) error { _, err := session.Table(flags.BotStockBrlTrade).Insert(&trade) if err != nil { return err } return nil } // CreateBotUserStockBrlFTHB // // @Description: // @receiver uo // @param ctx // @param session // @param stock // @return error func (uo *userOrderRepo) CreateBotUserStockBrlFTHB(session *xorm.Session, stock models.BotUserStockBrl) error { _, err := session.Table(flags.BotUserStockBrl).Insert(&stock) if err != nil { return err } return nil } // UpdateBotUserStockBrlByUserIdAndStockId // // @Description: // @receiver uo // @param ctx // @param session // @param userId // @param stockId // @param stock // @return error func (uo *userOrderRepo) UpdateBotUserStockBrlByUserIdAndStockId(session *xorm.Session, userId int64, stockId string, stock models.BotUserStockBrl) error { _, err := session.Table(flags.BotUserStockBrl). Where("user_id = ?", userId). Where("stock_id = ?", stockId). Update(&stock) if err != nil { return err } return nil } // StockBrlVoteDealType // // @Description: // @receiver uo // @param ctx // @param order // @return decimal.Decimal // @return error func (uo *userOrderRepo) StockBrlVoteDealType(order structure.ShareOrder) (decimal.Decimal, error) { var limitOrMarketPrice decimal.Decimal switch order.DealType { case flags.DealTypeLimited: // 限价 if len(order.LimitPrice) != 0 { limitOrMarketPrice = decimal.RequireFromString(order.LimitPrice) } case flags.DealTypeMarket: // 市价 if len(order.MarketPrice) != 0 { limitOrMarketPrice = decimal.RequireFromString(order.MarketPrice) } default: return decimal.Decimal{}, flags.ErrPublicFive } return limitOrMarketPrice, nil } // UpdateShareBrlVoteDealType // // @Description: // @receiver uo // @param ctx // @param order // @return decimal.Decimal // @return error func (uo *userOrderRepo) UpdateShareBrlVoteDealType(order *models.BotStockBrlTrade) (decimal.Decimal, error) { var limitOrMarketPrice decimal.Decimal switch order.DealType { case flags.DealTypeLimited: // 限价 if len(order.LimitPrice) != 0 { limitOrMarketPrice = decimal.RequireFromString(order.LimitPrice) } case flags.DealTypeMarket: // 市价 if len(order.MarketPrice) != 0 { limitOrMarketPrice = decimal.RequireFromString(order.MarketPrice) } default: return decimal.Decimal{}, flags.ErrPublicFive } if len(order.DealPrice) != 0 { dealPrice := decimal.RequireFromString(order.DealPrice) if !dealPrice.IsZero() { limitOrMarketPrice = dealPrice } } return limitOrMarketPrice, nil } // VerifyBotStockBrlTradeOrderId // // @Description: // @receiver uo // @param ctx // @param session // @return string // @return error func (uo *userOrderRepo) VerifyBotStockBrlTradeOrderId(session *xorm.Session) (string, error) { var orderId string for { // 生成订单ID orderId = orders.CreateRandCodeOrder(10) var orderList []models.BotStockBrlTrade err := session.Table(flags.BotStockBrlTrade). Where("order_id = ?", orderId). Find(&orderList) if err != nil || len(orderList) > 0 { applogger.Error("%v VerifyBotStockBrlTradeOrderId.Find:%v", common.ErrShareBrl, err) continue } break } return orderId, nil } // GetBotStockBrlTradeByOrderIdOrStatus // // @Description: // @receiver uo // @param ctx // @param session // @param orderId // @param status // @return *models.BotStockSgdTrade // @return error func (uo *userOrderRepo) GetBotStockBrlTradeByOrderIdOrStatus(session *xorm.Session, orderId string, status int) (*models.BotStockBrlTrade, error) { var botStockBrlTrade []models.BotStockBrlTrade if err := session.Table(flags.BotStockBrlTrade). Where("order_id = ?", orderId). Where("`status` = ?", status). Find(&botStockBrlTrade); err != nil { return nil, err } for _, value := range botStockBrlTrade { return &value, nil } return nil, nil }