You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1826 lines
67 KiB
1826 lines
67 KiB
package data
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"github.com/go-xorm/xorm"
|
|
"github.com/shopspring/decimal"
|
|
"matchmaking-system/internal/biz/structure"
|
|
"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"
|
|
"strconv"
|
|
"strings"
|
|
|
|
orders "matchmaking-system/internal/data/convert"
|
|
Moneyd "matchmaking-system/internal/data/tradedeal/money"
|
|
models "matchmaking-system/internal/pkg/model"
|
|
)
|
|
|
|
// GetBotMoneyTradeList
|
|
//
|
|
// @Description: 综合(现货|合约|外汇)订单列表查询
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param pageSize
|
|
// @param pageCount
|
|
// @param userId
|
|
// @param status
|
|
// @return []*models.BotMoneyTrade
|
|
// @return int64
|
|
// @return error
|
|
func (uo *userOrderRepo) GetBotMoneyTradeList(ctx context.Context, pageSize, pageCount, userId, status, marketType int64) ([]*models.BotMoneyTrade, int64, error) {
|
|
var totalCount int64
|
|
var err error
|
|
if marketType == 0 {
|
|
totalCount, err = uo.data.mysqlDB.Table(flags.BotMoneyTrade).
|
|
Where("user_id = ?", userId).
|
|
Where("status = ?", status).
|
|
Count()
|
|
} else {
|
|
totalCount, err = uo.data.mysqlDB.Table(flags.BotMoneyTrade).
|
|
Where("user_id = ?", userId).
|
|
Where("status = ?", status).
|
|
Where("market_type = ?", marketType).
|
|
Count()
|
|
}
|
|
if err != nil {
|
|
return nil, 0, flags.ErrMySqlDB
|
|
}
|
|
|
|
if totalCount == 0 {
|
|
return nil, 0, nil
|
|
}
|
|
|
|
var contractList []*models.BotMoneyTrade
|
|
if marketType == 0 {
|
|
err = uo.data.mysqlDB.Table(flags.BotMoneyTrade).
|
|
Where("user_id = ?", userId).
|
|
Where("status = ?", status).
|
|
Limit(int(pageSize), int(pageCount)).
|
|
Desc(GetOrderByStatusSort(status)).
|
|
Find(&contractList)
|
|
} else {
|
|
err = uo.data.mysqlDB.Table(flags.BotMoneyTrade).
|
|
Where("user_id = ?", userId).
|
|
Where("status = ?", status).
|
|
Where("market_type = ?", marketType).
|
|
Limit(int(pageSize), int(pageCount)).
|
|
Desc(GetOrderByStatusSort(status)).
|
|
Find(&contractList)
|
|
}
|
|
if err != nil {
|
|
return nil, 0, flags.ErrMySqlDB
|
|
}
|
|
|
|
var contractUpdateList []*models.BotMoneyTrade
|
|
for _, value := range contractList {
|
|
switch value.MarketType {
|
|
case flags.SpotsMarketType: // 现货
|
|
value.KeepDecimal = GetKeepDecimal(flags.SpotsSystemSetUpKey, value.StockId)
|
|
case flags.ContractMarketType: // 合约
|
|
value.KeepDecimal = GetKeepDecimal(flags.ContractSystemSetUpKey, value.StockId)
|
|
case flags.ForexMarketType: // 综合(现货|合约|外汇)
|
|
value.KeepDecimal = GetKeepDecimal(flags.ForexSystemSetUpKey, value.StockId)
|
|
default:
|
|
continue
|
|
}
|
|
contractUpdateList = append(contractUpdateList, value)
|
|
}
|
|
|
|
return contractUpdateList, totalCount, nil
|
|
}
|
|
|
|
// CreateBotMoneyTrade
|
|
//
|
|
// @Description: 综合(现货|合约|外汇)下单
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param userId
|
|
// @param order
|
|
// @return string
|
|
// @return error
|
|
func (uo *userOrderRepo) CreateBotMoneyTrade(ctx context.Context, userId int64, order structure.MoneyOrder) (string, error) {
|
|
// 1、综合(现货|合约|外汇)下单订阅
|
|
var err error
|
|
var system *structure.ForexSystem
|
|
stockId := strings.ToUpper(order.StockId)
|
|
switch order.Type {
|
|
case flags.SpotsMarketType: // 现货
|
|
_, ok := moneyZh.MoneySpotsMapSymbol.Load(strings.ToLower(stockId))
|
|
if ok {
|
|
go func() {
|
|
moneyZh.MoneySpotsMap <- []byte(stockId)
|
|
}()
|
|
}
|
|
system = &structure.ForexSystem{
|
|
MinPry: decimal.RequireFromString("1"),
|
|
MaxPry: decimal.RequireFromString("1"),
|
|
FaceValue: decimal.RequireFromString("1"),
|
|
CompelNum: decimal.RequireFromString("1"),
|
|
}
|
|
order.System = system
|
|
case flags.ContractMarketType: // 合约
|
|
_, ok := moneyZh.MoneyContractMapSymbol.Load(stockId)
|
|
if ok {
|
|
go func() {
|
|
moneyZh.MoneyContractMap <- []byte(stockId)
|
|
}()
|
|
}
|
|
systemContract, err := GetContractSystemSetUp(stockId)
|
|
if err != nil || systemContract == nil {
|
|
return flags.SetNull, flags.ErrContractOne
|
|
}
|
|
system = &structure.ForexSystem{
|
|
MinPry: systemContract.MinPry,
|
|
MaxPry: systemContract.MaxPry,
|
|
FaceValue: systemContract.FaceValue,
|
|
CompelNum: systemContract.CompelNum,
|
|
}
|
|
order.System = system
|
|
case flags.ForexMarketType: // 外汇
|
|
_, ok := moneyZh.MoneyForexMapSymbol.Load(stockId)
|
|
if ok {
|
|
go func() {
|
|
moneyZh.MoneyForexMap <- []byte(stockId)
|
|
}()
|
|
}
|
|
system, err = GetForexSystemSetUp(stockId)
|
|
if err != nil || system == nil {
|
|
return flags.SetNull, flags.ErrContractOne
|
|
}
|
|
order.System = system
|
|
default:
|
|
return flags.SetNull, flags.ErrShareTen
|
|
}
|
|
|
|
// 2、下单判定设置(false无设置|true止盈止损)
|
|
checkBool, stopWinPrice, stopLossPrice, err := MoneyVoteStopType(order)
|
|
if err != nil {
|
|
applogger.Error("%v CreateBotMoneyTrade.MoneyVoteStopType:%v", common.ErrMoney, err)
|
|
return flags.SetNull, err
|
|
}
|
|
|
|
// 3、下单判定设置(限价|市价)
|
|
limitOrMarketPrice, err := uo.MoneyVoteDealType(order)
|
|
if err != nil {
|
|
applogger.Error("%v CreateBotMoneyTrade.MoneyVoteDealType:%v", common.ErrMoney, err)
|
|
return flags.SetNull, err
|
|
}
|
|
|
|
// 4、下单判定设置(买涨|买跌)
|
|
if err = uo.MoneyVoteTradeType(order.TradeType, stopWinPrice, stopLossPrice, limitOrMarketPrice, checkBool); err != nil {
|
|
applogger.Error("%v CreateBotMoneyTrade.MoneyVoteTradeType:%v", common.ErrMoney, err)
|
|
return flags.SetNull, err
|
|
}
|
|
|
|
// 5、综合(现货|合约|外汇)下单(订单信息|资产信息)
|
|
var orderId string
|
|
if order.Type == flags.SpotsMarketType {
|
|
orderId, err = uo.MoneyOrdersDealDB(ctx, userId, order)
|
|
if err != nil || len(orderId) == 0 {
|
|
applogger.Error("%v CreateBotMoneyTrade.MoneyOrdersDealDB:%v", common.ErrMoney, err)
|
|
return flags.SetNull, err
|
|
}
|
|
} else {
|
|
orderId, err = uo.MoneyOrdersWriteDB(ctx, userId, order)
|
|
if err != nil || len(orderId) == 0 {
|
|
applogger.Error("%v CreateBotMoneyTrade.MoneyOrdersWriteDB:%v", common.ErrMoney, err)
|
|
return flags.SetNull, err
|
|
}
|
|
}
|
|
|
|
// 6、写入缓存列表(挂单缓存|持仓缓存),等待撮合计算
|
|
marketStatus, tallyCache, err := Moneyd.MoneyCacheDeal(ctx, userId, orderId, limitOrMarketPrice.String(), order)
|
|
if err != nil || tallyCache == nil {
|
|
applogger.Error("%v CreateBotMoneyTrade.MoneyCacheDeal:%v", common.ErrMoney, err)
|
|
return flags.SetNull, err
|
|
}
|
|
|
|
// 7、综合(现货|合约|外汇)市价单处理
|
|
switch marketStatus {
|
|
case setting.MarketMoneyClose: // TODO:现货市价平仓
|
|
if _, err = MoneyOrdersClosingDB(context.Background(), uo.data.mysqlDB, tallyCache.UserId, order, orderId, limitOrMarketPrice.String()); err != nil {
|
|
return flags.SetNull, err
|
|
}
|
|
default:
|
|
// 8、(合约|外汇)市价下单(开仓|平仓)处理(订单信息|资产信息|手续费|返佣|资产详情记录)
|
|
if marketStatus == setting.MarketMoneyPosition {
|
|
if err = MoneyOpenPosition(ctx, uo.data.mysqlDB, userId, orderId, tallyCache.OpenPrice, order); err != nil {
|
|
applogger.Error("%v CreateBotMoneyTrade.MoneyOpenPosition:%v", common.ErrMoney, err)
|
|
return flags.SetNull, err
|
|
}
|
|
}
|
|
// 9、写入(挂单|持仓)缓存列表
|
|
if err = Moneyd.MoneyPushAddCache(Reds, marketStatus, tallyCache); err != nil {
|
|
applogger.Error("%v CreateBotMoneyTrade.MoneyPushAddCache:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrCacheDB
|
|
}
|
|
// TODO: 10、现货不参与用户订单缓存和管理员订单订阅缓存
|
|
if order.Type != flags.SpotsMarketType {
|
|
// 11、写入用户订单订阅缓存列表
|
|
orderIdKey := virtual.OrderIdListKey(setting.MoneySubscribe, userId)
|
|
if err = Moneyd.MoneyHashSetOrderId(Reds, orderIdKey, tallyCache); err != nil {
|
|
applogger.Error("%v CreateBotMoneyTrade.MoneyPushAddOrder:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrCacheDB
|
|
}
|
|
|
|
// 12、写入管理员订单订阅缓存列表
|
|
if err = Moneyd.MoneyHashSetOrderId(Reds, setting.AdminMoneySubscribe, tallyCache); err != nil {
|
|
applogger.Error("%v CreateBotMoneyTrade.MoneyHashSetOrderId:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrCacheDB
|
|
}
|
|
}
|
|
}
|
|
|
|
return orderId, nil
|
|
}
|
|
|
|
// MoneyOrdersWriteDB
|
|
//
|
|
// @Description: 综合(现货|合约|外汇)下单处理
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param userId
|
|
// @param order
|
|
// @return string
|
|
// @return error
|
|
func (uo *userOrderRepo) MoneyOrdersWriteDB(ctx context.Context, userId int64, order structure.MoneyOrder) (string, error) {
|
|
session := uo.data.mysqlDB.NewSession()
|
|
defer session.Close()
|
|
err := session.Begin()
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersWriteDB.NewSession:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 查询当前下单用户可用账户金额和冻结金额
|
|
var usable, frozen, usableNo, frozenNo decimal.Decimal
|
|
usable, frozen, _, err = uo.GetBotUserMoney(session, userId, flags.MoneyUnit)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersWriteDB.GetBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 检查用户订单下单资产
|
|
if usable.IsZero() || usable.IsNegative() || frozen.IsNegative() {
|
|
return flags.SetNull, flags.ErrPublicOne
|
|
}
|
|
|
|
// 查询当前下单用户可用非账户和冻结金额
|
|
var checkCount int
|
|
if order.StockId != flags.MoneyUnit {
|
|
usableNo, frozenNo, checkCount, err = uo.GetBotUserMoney(session, userId, order.StockId)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersWriteDB.GetBotUserMoney.Fei:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("下单可用金额:%v", usable)
|
|
applogger.Debug("下单冻结金额:%v", frozen)
|
|
applogger.Debug("非下单可用金额:%v", usableNo)
|
|
applogger.Debug("非下单冻结金额:%v", frozenNo)
|
|
}
|
|
// 写入订单信息
|
|
orderId, err := uo.VerifyBotMoneyTradeOrderId(session)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersWriteDB.VerifyBotMoneyTradeOrderId:%v", common.ErrMoney, err)
|
|
return flags.SetNull, err
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("下单Id:%v", orderId)
|
|
applogger.Debug("下单杠杆:%v", order.PryNum)
|
|
}
|
|
|
|
// 写入订单表
|
|
botMoneyTrade := orders.BotMoneyTrade(ctx, userId, orderId, order)
|
|
if err = uo.CreatBotMoneyTrade(session, botMoneyTrade); err != nil {
|
|
applogger.Error("%v MoneyOrdersWriteDB.CreatBotMoneyTrade:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 订单总金额 = 保证金 + 手续费
|
|
earnestMoney := decimal.RequireFromString(order.EarnestMoney) // 保证金
|
|
serviceCost := decimal.RequireFromString(order.ServiceCost) // 手续费
|
|
totalMoney := earnestMoney.Add(serviceCost)
|
|
|
|
// 总金额下单判定
|
|
if usable.Cmp(totalMoney) < 0 {
|
|
return flags.SetNull, flags.ErrPublicOne
|
|
}
|
|
|
|
// (买涨|买跌)处理
|
|
var usableNew, frozenNew, usableNewNo, frozenNewNo decimal.Decimal
|
|
usableNew = usable.Sub(totalMoney) // 可用资产
|
|
frozenNew = frozen.Add(totalMoney) // 冻结资产
|
|
if order.StockId != flags.MoneyUnit {
|
|
usableNewNo = usableNo // 可用非资产
|
|
frozenNewNo = frozenNo // 冻结非资产
|
|
}
|
|
|
|
// 检查用户订单下单资产
|
|
if usableNew.IsNegative() || usableNew.IsZero() {
|
|
return flags.SetNull, flags.ErrPublicTow
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("下单后用户可用资产:%v", usableNew)
|
|
applogger.Debug("下单后用户冻结资产:%v", frozenNew)
|
|
applogger.Debug("下单后用户非可用资产:%v", usableNewNo)
|
|
applogger.Debug("下单后用户非冻结资产:%v", frozenNewNo)
|
|
}
|
|
|
|
// 更新用户资产信息
|
|
userMoneyUSDT := orders.UpdateBotUserMoney(ctx, usableNew.String(), frozenNew.String())
|
|
if err = uo.UpdateBotUserMoney(session, userId, flags.MoneyUnit, userMoneyUSDT); err != nil {
|
|
applogger.Error("%v MoneyOrdersWriteDB.UpdateBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 更新非资产信息
|
|
if order.StockId != flags.MoneyUnit {
|
|
if checkCount == 0 {
|
|
userMoneySymbol := orders.CreatBotUserMoney(ctx, userId, usableNewNo.String(), frozenNewNo.String(), order)
|
|
err = uo.CreatBotUserMoney(session, userMoneySymbol)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersWriteDB.CreatBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
} else {
|
|
userMoney := orders.UpdateBotUserMoney(ctx, usableNewNo.String(), frozenNewNo.String())
|
|
if err = uo.UpdateBotUserMoney(session, userId, order.StockId, userMoney); err != nil {
|
|
applogger.Error("%v MoneyOrdersWriteDB.UpdateBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
}
|
|
}
|
|
|
|
if err = session.Commit(); err != nil {
|
|
applogger.Error("%v MoneyOrdersWriteDB.Commit:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
return orderId, nil
|
|
}
|
|
|
|
// MoneyOpenPosition
|
|
//
|
|
// @Description: 综合(现货|合约|外汇)开仓处理
|
|
// @param ctx
|
|
// @param db
|
|
// @param userId
|
|
// @param orderId
|
|
// @param openPrice
|
|
// @param order
|
|
// @return error
|
|
func MoneyOpenPosition(ctx context.Context, db *xorm.EngineGroup, userId int64, orderId, openPrice string, order structure.MoneyOrder) error {
|
|
session := db.NewSession()
|
|
defer session.Close()
|
|
err := session.Begin()
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.NewSession:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
|
|
// 查询当前下单用户可用账户金额和冻结金额
|
|
var usable, frozen, usableNo, frozenNo decimal.Decimal
|
|
usable, frozen, _, err = Uo.GetBotUserMoney(session, userId, flags.MoneyUnit)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.GetBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("下单可用金额:%v", usable)
|
|
applogger.Debug("下单冻结金额:%v", frozen)
|
|
applogger.Debug("下单开仓价格:%v", openPrice)
|
|
}
|
|
|
|
if order.StockId != flags.MoneyUnit {
|
|
usableNo, frozenNo, _, err = Uo.GetBotUserMoney(session, userId, order.StockId)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.GetBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
}
|
|
|
|
earnestMoney := decimal.RequireFromString(order.EarnestMoney) // 下单保证金
|
|
openOrderNumber := decimal.RequireFromString(order.OrderNumber) // 下单仓位
|
|
serviceCost := decimal.RequireFromString(order.ServiceCost) // 下单手续费
|
|
totalMoney := earnestMoney.Add(serviceCost) // 下单总金额 = (订单手续费 + 保证金)
|
|
openOrderPrice := decimal.RequireFromString(openPrice) // 开仓价格(下单金额)
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("下单订单杠杆:%v", order.PryNum)
|
|
applogger.Debug("下单保证金:%v", order.EarnestMoney)
|
|
applogger.Debug("下单订单数量:%v", order.OrderNumber)
|
|
applogger.Debug("下单订单手续费:%v", order.ServiceCost)
|
|
}
|
|
// 手续费记录
|
|
var cost string
|
|
openPriceNew := openOrderPrice.Mul(openOrderNumber).String() // 开仓手续费 = 开仓价格 * 仓位数 * 手续费比例
|
|
switch order.Type {
|
|
case flags.SpotsMarketType: // 现货
|
|
cost, err = Uo.CalculateHandlingFees(ctx, session, int(userId), flags.SpotsMarketType, flags.OpenBrokType, orderId, openPriceNew, "1")
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.CalculateHandlingFees:%v", common.ErrMoney, err)
|
|
return err
|
|
}
|
|
case flags.ContractMarketType: // 合约
|
|
cost, err = Uo.CalculateHandlingFees(ctx, session, int(userId), flags.ContractMarketType, flags.OpenBrokType, orderId, openPriceNew, "1")
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.CalculateHandlingFees:%v", common.ErrMoney, err)
|
|
return err
|
|
}
|
|
case flags.ForexMarketType: // 外汇
|
|
cost, err = Uo.CalculateHandlingFees(ctx, session, int(userId), flags.ForexMarketType, flags.OpenBrokType, orderId, openPriceNew, "1")
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.CalculateHandlingFees:%v", common.ErrMoney, err)
|
|
return err
|
|
}
|
|
}
|
|
openServiceCost := decimal.RequireFromString(cost) // 开仓手续费
|
|
openTotalMoney := earnestMoney.Add(openServiceCost) // 开仓总金额 = (保证金 + 开仓手续费)
|
|
floatPrice := totalMoney.Sub(openTotalMoney) // 计算容差 = 下单总额 - 开仓总额
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("开仓订单价格:%v", openOrderPrice)
|
|
applogger.Debug("开仓仓位:%v", openOrderNumber)
|
|
applogger.Debug("开仓手续费:%v", openServiceCost)
|
|
applogger.Debug("开仓总金额:%v", openTotalMoney)
|
|
applogger.Debug("下单开仓总金额容差值:%v", floatPrice)
|
|
}
|
|
|
|
usableNew := usable.Add(floatPrice) // 可用资产(处理容差值)
|
|
frozenNew := frozen.Sub(totalMoney).Add(earnestMoney) // 冻结资产 = 冻结资产 - 下单冻结资产 + 开仓保证金
|
|
usableNoNew := usableNo.Add(openOrderNumber) // 非可用资产
|
|
frozenNoNew := frozenNo // 非冻结资产
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("下单后用户可用资产:%v", usableNew)
|
|
applogger.Debug("下单后用户冻结资产:%v", frozenNew)
|
|
applogger.Debug("下单冻结资产:%v", frozen)
|
|
applogger.Debug("下单后的冻结总资产:%v", totalMoney)
|
|
applogger.Debug("开仓后的保证金:%v", earnestMoney)
|
|
applogger.Debug("下单后用户冻结资产:%v", frozenNew)
|
|
applogger.Debug("下单后用户可用资产:%v", usableNew)
|
|
}
|
|
|
|
// 处理资产信息
|
|
userMoneyUSDT := orders.UpdateBotUserMoney(ctx, usableNew.String(), frozenNew.String())
|
|
if err = Uo.UpdateBotUserMoney(session, userId, flags.MoneyUnit, userMoneyUSDT); err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.UpdateBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
|
|
// 更新非资产信息
|
|
if order.StockId != flags.MoneyUnit {
|
|
userMoney := orders.UpdateBotUserMoney(ctx, usableNoNew.String(), frozenNoNew.String())
|
|
if err = Uo.UpdateBotUserMoney(session, userId, order.StockId, userMoney); err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.UpdateBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
}
|
|
|
|
// 处理订单信息(成交价|仓位|开仓时间|订单总金额|手续费|持仓状态)
|
|
trade := orders.UpdateOpenBotMoneyTrade(ctx, openPrice, openOrderNumber.String(), openTotalMoney.String(), openServiceCost.String())
|
|
if err = Uo.UpdateBotMoneyTradeByOrderId(session, orderId, trade); err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.UpdateBotMoneyTradeByOrderId:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
|
|
// 返佣记录|资金信息|资金详情信息
|
|
switch order.Type {
|
|
case flags.SpotsMarketType: // 现货
|
|
if err = Uo.MoneyRebateCalculation(ctx, session, int(userId), flags.SpotsMarketType, flags.OpenBrokType, flags.OpenMRebate, cost, orderId); err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.MoneyRebateCalculation:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
case flags.ContractMarketType: // 合约
|
|
if err = Uo.MoneyRebateCalculation(ctx, session, int(userId), flags.ContractMarketType, flags.OpenBrokType, flags.OpenMRebate, cost, orderId); err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.MoneyRebateCalculation:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
case flags.ForexMarketType: // 外汇
|
|
if err = Uo.MoneyRebateCalculation(ctx, session, int(userId), flags.ForexMarketType, flags.OpenBrokType, flags.OpenMRebate, cost, orderId); err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.MoneyRebateCalculation:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
default:
|
|
}
|
|
|
|
// 更改交易日志记录方式
|
|
var list []models.BotUserMoneyLog
|
|
qData0 := orders.CreatBotUserMoneyLog(ctx, userId, flags.CostMoney, flags.MoneyUnit, NegativeValue(openServiceCost.String()), orderId) // 资金变动明细表(开仓手续费)
|
|
qData1 := orders.CreatBotUserMoneyLog(ctx, userId, flags.Freeze, flags.MoneyUnit, NegativeValue(earnestMoney.String()), orderId) // 资金变动明细表(开仓保证金)
|
|
qData2 := orders.CreatBotUserMoneyLog(ctx, userId, flags.ChangeInto, order.StockId, openOrderNumber.String(), orderId) // 资金变动明细表(非资产)
|
|
list = append(list, qData0, qData1, qData2)
|
|
|
|
// 批量写入数据信息
|
|
if err = Uo.CreatBotUserMoneyLogList(session, list); err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.CreatBotUserMoneyLogList:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
|
|
if err = session.Commit(); err != nil {
|
|
applogger.Error("%v MoneyOpenPosition.Commit:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// MoneyClosingPosition
|
|
//
|
|
// @Description: 综合(现货|合约|外汇)平仓处理
|
|
// @param ctx
|
|
// @param db
|
|
// @param orderId
|
|
// @param price
|
|
// @param order
|
|
// @return error
|
|
func MoneyClosingPosition(ctx context.Context, db *xorm.EngineGroup, orderId string, price string, order structure.MoneyOrder, status int) error {
|
|
session := db.NewSession()
|
|
defer session.Close()
|
|
err := session.Begin()
|
|
if err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.NewSession:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
|
|
// TODO: 处理状态
|
|
var closeStatus int
|
|
switch order.Type {
|
|
case flags.SpotsMarketType:
|
|
closeStatus = flags.EntrustStatus
|
|
default:
|
|
closeStatus = flags.PositionStatus
|
|
}
|
|
|
|
// 查询订单信息
|
|
tread, err := Uo.GetBotMoneyTradeByOrderId(session, orderId, closeStatus)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.GetBotMoneyTradeByOrderId:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
var userId int64
|
|
var dealPrice, earnestMoney, orderNumber, totalAmount, serviceCost, pryNum decimal.Decimal
|
|
if tread != nil {
|
|
userId = int64(tread.UserId) // 用户Id
|
|
earnestMoney = decimal.RequireFromString(tread.MarketMoney) // 开仓保证金
|
|
orderNumber = decimal.RequireFromString(tread.OrderNumber) // 下单数量
|
|
dealPrice = decimal.RequireFromString(tread.DealPrice) // 开仓价格
|
|
totalAmount = decimal.RequireFromString(tread.OrderMoney) // 开仓总金额
|
|
serviceCost = decimal.RequireFromString(tread.ServiceCost) // 开仓手续费
|
|
pryNum = decimal.RequireFromString(strconv.Itoa(tread.PryNum)) // 杠杆
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("下单开仓用户Id:%v", userId)
|
|
applogger.Debug("下单开仓开仓价格:%v", dealPrice)
|
|
applogger.Debug("下单开仓保证金:%v", earnestMoney)
|
|
applogger.Debug("下单开仓订单数量:%v", orderNumber)
|
|
applogger.Debug("下单开仓总金额:%v", totalAmount)
|
|
applogger.Debug("下单开仓手续费:%v", serviceCost)
|
|
applogger.Debug("下单开仓杠杆:%v", pryNum)
|
|
}
|
|
|
|
// 查询当前下单用户可用账户金额和冻结金额
|
|
var usable, frozen, usableNo, frozenNo decimal.Decimal
|
|
usable, frozen, _, err = Uo.GetBotUserMoney(session, userId, flags.MoneyUnit)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.GetBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("下单可用金额:%v", usable)
|
|
applogger.Debug("下单冻结金额:%v", frozen)
|
|
}
|
|
|
|
// 查询当前下单用户可用非账户和冻结金额
|
|
if order.StockId != flags.MoneyUnit {
|
|
usableNo, frozenNo, _, err = Uo.GetBotUserMoney(session, userId, order.StockId)
|
|
if err != nil {
|
|
applogger.Error("%vMoneyClosingPosition.GetBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("非下单可用金额:%v", usableNo)
|
|
applogger.Debug("非下单冻结金额:%v", frozenNo)
|
|
}
|
|
|
|
// TODO: 平仓手续费处理
|
|
var cost string
|
|
closeFaceValue := order.System.FaceValue // 面值
|
|
closePrice := decimal.RequireFromString(price) // 平仓价格
|
|
cloePriceCost := closePrice.Mul(orderNumber).String() // 平仓手续费 = 平仓价格 * 仓位数 * 手续费比例 * 面值
|
|
switch order.Type {
|
|
case flags.SpotsMarketType: // 现货
|
|
cost, err = Uo.CalculateHandlingFees(ctx, session, int(userId), flags.SpotsMarketType, flags.ClosingBrokType, orderId, cloePriceCost, closeFaceValue.String())
|
|
if err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.CalculateHandlingFees:%v", common.ErrMoney, err)
|
|
return err
|
|
}
|
|
case flags.ContractMarketType: // 合约
|
|
cost, err = Uo.CalculateHandlingFees(ctx, session, int(userId), flags.ContractMarketType, flags.ClosingBrokType, orderId, cloePriceCost, closeFaceValue.String())
|
|
if err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.CalculateHandlingFees:%v", common.ErrMoney, err)
|
|
return err
|
|
}
|
|
case flags.ForexMarketType: // 外汇
|
|
cost, err = Uo.CalculateHandlingFees(ctx, session, int(userId), flags.ForexMarketType, flags.ClosingBrokType, orderId, cloePriceCost, closeFaceValue.String())
|
|
if err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.CalculateHandlingFees:%v", common.ErrMoney, 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).Mul(closeFaceValue).Mul(pryNum)
|
|
case flags.TradeTypeSell: // 买跌
|
|
subPrice = dealPrice.Sub(closePrice)
|
|
resultPrice = subPrice.Mul(orderNumber).Mul(closeFaceValue).Mul(pryNum)
|
|
default:
|
|
}
|
|
|
|
// 用户资产账户
|
|
usableNew = usable.Add(resultPrice).Add(earnestMoney).Sub(closeServiceCost) // 可用资产 = 原可用资产 + ((正负)盈亏*面值) + 保证金 - 手续费
|
|
frozenNew = frozen.Sub(earnestMoney) // 冻结资产
|
|
// 用户非资产账户
|
|
if order.StockId != flags.MoneyUnit {
|
|
usableNewNo = usableNo.Sub(orderNumber) // 可用非资产 = 原可用非资产 - 下单仓位数
|
|
frozenNewNo = frozenNo // 可用非冻结资产
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("可用资产:%v", usableNew)
|
|
applogger.Debug("冻结资产:%v", frozenNew)
|
|
applogger.Debug("可用非资产:%v", usableNewNo)
|
|
applogger.Debug("冻结非资产:%v", frozenNewNo)
|
|
}
|
|
|
|
// 平仓(处理资产表(资产))
|
|
userMoneyUSDT := orders.UpdateBotUserMoney(ctx, usableNew.String(), frozenNew.String())
|
|
if err = Uo.UpdateBotUserMoney(session, userId, flags.MoneyUnit, userMoneyUSDT); err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.UpdateBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
|
|
// 平仓(处理资产表(非资产))
|
|
if order.StockId != flags.MoneyUnit {
|
|
userMoney := orders.UpdateBotUserMoney(ctx, usableNewNo.String(), frozenNewNo.String())
|
|
if err = Uo.UpdateBotUserMoney(session, userId, order.StockId, userMoney); err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.UpdateBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
}
|
|
|
|
// 平仓(处理订单信息(平仓价|保证金|平仓|订单总金额|平仓手续费|完成订单))
|
|
trade := orders.UpdateCloseBotMoneyTrade(ctx, price, earnestMoney.String(), totalAmount.String(), cost, status)
|
|
if err = Uo.UpdateBotMoneyTradeByOrderId(session, orderId, trade); err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.UpdateBotMoneyTradeByOrderId:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
|
|
// TODO: 平仓(返佣记录表|资产表|资金变动表)
|
|
switch order.Type {
|
|
case flags.SpotsMarketType: // 现货
|
|
if err = Uo.MoneyRebateCalculation(ctx, session, int(userId), flags.SpotsMarketType, flags.ClosingBrokType, flags.CloseMRebate, cost, orderId); err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.MoneyRebateCalculation:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
case flags.ContractMarketType: // 合约
|
|
if err = Uo.MoneyRebateCalculation(ctx, session, int(userId), flags.ContractMarketType, flags.ClosingBrokType, flags.CloseMRebate, cost, orderId); err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.MoneyRebateCalculation:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
case flags.ForexMarketType: // 外汇
|
|
if err = Uo.MoneyRebateCalculation(ctx, session, int(userId), flags.ForexMarketType, flags.ClosingBrokType, flags.CloseMRebate, cost, orderId); err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.MoneyRebateCalculation:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
}
|
|
|
|
// 更改交易日志记录方式
|
|
var list []models.BotUserMoneyLog
|
|
qData0 := orders.CreatBotUserMoneyLog(ctx, userId, flags.CostMoney, flags.MoneyUnit, NegativeValue(closeServiceCost.String()), orderId) // 平仓(资金变动明细表(-平仓手续费))
|
|
qData1 := orders.CreatBotUserMoneyLog(ctx, userId, flags.Thaw, flags.MoneyUnit, earnestMoney.String(), orderId) // 平仓(资金变动明细表(+保证金))
|
|
qData2 := orders.CreatBotUserMoneyLog(ctx, userId, flags.TransferOut, order.StockId, NegativeValue(orderNumber.String()), orderId) // 平仓(资金变动明细表(-非资产))
|
|
list = append(list, qData0, qData1, qData2)
|
|
|
|
// 平仓(资金变动明细表(正负盈亏))
|
|
if resultPrice.IsNegative() {
|
|
qData3 := orders.CreatBotUserMoneyLog(ctx, userId, flags.TransferOut, flags.MoneyUnit, resultPrice.String(), orderId)
|
|
list = append(list, qData3)
|
|
} else {
|
|
qData4 := orders.CreatBotUserMoneyLog(ctx, userId, flags.ChangeInto, flags.MoneyUnit, resultPrice.String(), orderId)
|
|
list = append(list, qData4)
|
|
}
|
|
|
|
// 平仓(批量写入交易订单日志信息)
|
|
if err = Uo.CreatBotUserMoneyLogList(session, list); err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.CreatBotUserMoneyLogList:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
|
|
if err = session.Commit(); err != nil {
|
|
applogger.Error("%v MoneyClosingPosition.Commit:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// UpdateBotMoneyStopByOrderId
|
|
//
|
|
// @Description: 综合(现货|合约|外汇)设置止盈止损
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param order
|
|
// @return bool
|
|
// @return error
|
|
func (uo *userOrderRepo) UpdateBotMoneyStopByOrderId(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 UpdateBotMoneyStopByOrderId.NewSession:%v", common.ErrMoney, err)
|
|
return false, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 设置止盈止损判定
|
|
trade, err := uo.GetBotMoneyTradeByOrderId(session, order.OrderId, flags.PositionStatus)
|
|
if err != nil || trade == nil {
|
|
applogger.Error("%v UpdateBotMoneyStopByOrderId.GetBotMoneyTradeByOrderId:%v", common.ErrMoney, err)
|
|
return false, flags.ErrMySqlDB
|
|
}
|
|
// 下单信息
|
|
checkBool, stopWinPrice, stopLossPrice, err := uo.UpdateMoneyVoteStopType(order)
|
|
if err != nil {
|
|
applogger.Error("%v UpdateBotMoneyStopByOrderId.UpdateMoneyVoteStopType:%v", common.ErrMoney, err)
|
|
return false, err
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("获取当前止盈止损数据:%v,%v,%v", checkBool, stopWinPrice, stopLossPrice)
|
|
}
|
|
|
|
// 下单判定设置(限价|市价|开仓价)
|
|
limitOrMarketPrice, err := uo.UpdateMoneyVoteDealType(trade)
|
|
if err != nil {
|
|
applogger.Error("%v UpdateBotMoneyStopByOrderId.UpdateMoneyVoteDealType:%v", common.ErrMoney, err)
|
|
return false, err
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("获取当前开仓价格:%v", limitOrMarketPrice)
|
|
}
|
|
|
|
// 下单判定设置(买涨|买跌)
|
|
if err = uo.MoneyVoteTradeType(int64(trade.TradeType), stopWinPrice, stopLossPrice, limitOrMarketPrice, checkBool); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyStopByOrderId.MoneyVoteTradeType:%v", common.ErrMoney, err)
|
|
return false, err
|
|
}
|
|
|
|
// 更新订单表
|
|
botStockTrade := orders.BotMoneyStopByOrderId(ctx, order)
|
|
err = uo.UpdateBotMoneyTradeByOrderId(session, order.OrderId, botStockTrade)
|
|
if err != nil {
|
|
applogger.Error("%v UpdateBotMoneyStopByOrderId.Update:%v", common.ErrMoney, err)
|
|
return false, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 修改挂单缓存队列
|
|
entrust, err := LoadLRangeList(setting.MarketMoneyPosition)
|
|
if err != nil {
|
|
applogger.Error("%v UpdateBotMoneyStopByOrderId.LoadLRangeList:%v", common.ErrMoney, err)
|
|
return false, flags.ErrCacheDB
|
|
}
|
|
for key, value := range entrust {
|
|
var entrustJson Moneyd.MoneyTallyCache
|
|
if err = json.Unmarshal([]byte(value), &entrustJson); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyStopByOrderId.Unmarshal:%v", common.ErrMoney, err)
|
|
return false, flags.ErrCacheDB
|
|
}
|
|
entrustJson.Order.StopType = order.StopType
|
|
entrustJson.Order.StopWinPrice = order.StopWinPrice
|
|
entrustJson.Order.StopLossPrice = order.StopLossPrice
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("修改缓存中的止盈止损Type:%v", entrustJson.Order.StopType)
|
|
applogger.Debug("修改缓存中的止盈:%v", entrustJson.Order.StopWinPrice)
|
|
applogger.Debug("修改缓存中的止损:%v", entrustJson.Order.StopLossPrice)
|
|
}
|
|
var data []byte
|
|
data, err = json.Marshal(&entrustJson)
|
|
if err != nil {
|
|
applogger.Error("%v UpdateBotMoneyStopByOrderId.Marshal:%v", common.ErrMoney, err)
|
|
return false, flags.ErrCacheDB
|
|
}
|
|
if order.OrderId == entrustJson.OrderId {
|
|
if err = Reds.HSet(context.Background(), setting.MarketMoneyPosition, key, string(data)).Err(); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyStopByOrderId.HSet:%v", common.ErrMoney, err)
|
|
return false, flags.ErrCacheDB
|
|
}
|
|
}
|
|
}
|
|
|
|
if err = session.Commit(); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyStopByOrderId.Commit:%v", common.ErrMoney, err)
|
|
return false, flags.ErrMySqlDB
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
// UpdateBotMoneyCancelByOrderId
|
|
//
|
|
// @Description: 综合(现货|合约|外汇)撤单
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param orderId
|
|
// @return bool
|
|
// @return error
|
|
func (uo *userOrderRepo) UpdateBotMoneyCancelByOrderId(ctx context.Context, orderId string) (bool, error) {
|
|
session := uo.data.mysqlDB.NewSession()
|
|
defer session.Close()
|
|
err := session.Begin()
|
|
if err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.NewSession:%v", common.ErrMoney, err)
|
|
return false, flags.ErrMySqlDB
|
|
}
|
|
|
|
// get BotMoneyTrade
|
|
tread, err := uo.GetBotMoneyTradeByOrderId(session, orderId, flags.EntrustStatus)
|
|
if err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.GetBotMoneyTradeByOrderId:%v", common.ErrMoney, err)
|
|
return false, flags.ErrMySqlDB
|
|
}
|
|
var userId int64
|
|
var earnestMoneyT, serviceCostT, symbol, orderNumber string
|
|
if tread != nil {
|
|
userId = int64(tread.UserId)
|
|
earnestMoneyT = tread.MarketMoney
|
|
serviceCostT = tread.ServiceCost
|
|
orderNumber = tread.OrderNumber
|
|
symbol = tread.StockId
|
|
}
|
|
|
|
// get BotUserStock By USD
|
|
var usable, frozen, usableNo, frozenNo decimal.Decimal
|
|
usable, frozen, _, err = uo.GetBotUserMoney(session, userId, flags.MoneyUnit)
|
|
if err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.GetBotUserMoney:%v", common.ErrMoney, err)
|
|
return false, flags.ErrMySqlDB
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("用户原始可用资金:%v", usable)
|
|
applogger.Debug("用户原始冻结资金:%v", frozen)
|
|
}
|
|
|
|
if symbol != flags.MoneyUnit {
|
|
usableNo, frozenNo, _, err = uo.GetBotUserMoney(session, userId, tread.StockId)
|
|
if err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.GetBotUserMoney:%v", common.ErrMoney, err)
|
|
return false, flags.ErrPublicFour
|
|
}
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("用户原始可用非资金:%v", usableNo)
|
|
applogger.Debug("用户原始冻结非资金:%v", frozenNo)
|
|
}
|
|
|
|
// 更新订单信息
|
|
botStockTrade := orders.BotMoneyCancelByOrderId(ctx)
|
|
if err = uo.UpdateBotMoneyTradeByOrderId(session, orderId, botStockTrade); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.UpdateBotMoneyTradeByOrderId:%v", common.ErrMoney, err)
|
|
return false, flags.ErrPublicFour
|
|
}
|
|
|
|
// Operational Spot Asset Table
|
|
earnestMoney := decimal.RequireFromString(earnestMoneyT) // 保证金
|
|
serviceCost := decimal.RequireFromString(serviceCostT) // 订单手续费
|
|
totalMoney := earnestMoney.Add(serviceCost) // 订单总金额
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("撤单用户ID:%v", userId)
|
|
applogger.Debug("下单交易对:%v", symbol)
|
|
applogger.Debug("撤单订单保证金:%v", earnestMoneyT)
|
|
applogger.Debug("撤单手续费:%v", serviceCostT)
|
|
applogger.Debug("撤单订单数量:%v", orderNumber)
|
|
applogger.Debug("撤单总金额数量:%v", totalMoney)
|
|
}
|
|
|
|
// Update total asset data
|
|
usableNew := usable.Add(totalMoney) // 用户总资产
|
|
frozenNew := frozen.Sub(totalMoney) // 用户冻结资产
|
|
usableNoNew := usableNo // 用户非可用资产
|
|
frozenNoNew := frozenNo // 用户非冻结资产
|
|
|
|
// 检查用户订单撤单资产
|
|
if frozenNew.IsNegative() {
|
|
return false, flags.ErrContractSeven
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("用户撤单可用总资产:%v", usableNew)
|
|
applogger.Debug("用户撤单冻结总资产:%v", frozenNew)
|
|
applogger.Debug("用户非撤单可用总资产:%v", usableNoNew)
|
|
applogger.Debug("用户非撤单冻结总资产:%v", frozenNoNew)
|
|
}
|
|
|
|
userMoneyUSD := orders.UpdateBotUserMoney(ctx, usableNew.String(), frozenNew.String())
|
|
if err = uo.UpdateBotUserMoney(session, userId, flags.MoneyUnit, userMoneyUSD); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.UpdateBotUserMoney:%v", common.ErrMoney, err)
|
|
return false, flags.ErrMySqlDB
|
|
}
|
|
|
|
if symbol != flags.MoneyUnit {
|
|
userMoney := orders.UpdateBotUserMoney(ctx, usableNoNew.String(), frozenNoNew.String())
|
|
if err = uo.UpdateBotUserMoney(session, userId, tread.StockId, userMoney); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.UpdateBotUserMoney:%v", common.ErrMoney, err)
|
|
return false, flags.ErrMySqlDB
|
|
}
|
|
}
|
|
|
|
// 清理挂单缓存信息
|
|
if err = Reds.HDel(context.Background(), setting.MarketMoneyEntrust, orderId).Err(); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.HDel:%v", common.ErrMoney, err)
|
|
return false, flags.ErrCacheDB
|
|
}
|
|
|
|
if tread.MarketType != flags.SpotsMarketType {
|
|
// 撤单更新订阅缓存订单状态
|
|
userSubKey := virtual.OrderIdListKey(setting.MoneySubscribe, userId)
|
|
if err = UpdateMoneySubscribeHashStatusByOrderId(orderId, userSubKey, flags.Cancel, flags.SetNull); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.MoneySubscribe:%v", common.ErrMoney, err)
|
|
return false, flags.ErrCacheDB
|
|
}
|
|
|
|
// 撤单更新管理员订阅缓存订单状态
|
|
if err = UpdateMoneySubscribeHashStatusByOrderId(orderId, setting.AdminMoneySubscribe, flags.Cancel, flags.SetNull); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.AdminMoneySubscribe:%v", common.ErrMoney, err)
|
|
return false, flags.ErrCacheDB
|
|
}
|
|
}
|
|
|
|
if err = session.Commit(); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.Commit:%v", common.ErrMoney, err)
|
|
return false, flags.ErrMySqlDB
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
// UpdateBotMoneyClosingByOrderId
|
|
//
|
|
// @Description: 综合(现货|合约|外汇)平仓
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param orderId
|
|
// @return bool
|
|
// @return error
|
|
func (uo *userOrderRepo) UpdateBotMoneyClosingByOrderId(ctx context.Context, orderId string) (bool, error) {
|
|
// 1、订单信息
|
|
entrust, err := Reds.HGet(context.Background(), setting.MarketMoneyPosition, orderId).Result()
|
|
if err != nil {
|
|
applogger.Error("%v UpdateBotMoneyClosingByOrderId.MarketMoneyPosition.HGet:%v", common.ErrMoney, err)
|
|
return false, flags.ErrMySqlDB
|
|
}
|
|
|
|
var entrustJson Moneyd.MoneyTallyCache
|
|
if err = json.Unmarshal([]byte(entrust), &entrustJson); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyClosingByOrderId.Unmarshal:%v", common.ErrMoney, err)
|
|
return false, flags.ErrCacheDB
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("手动平仓:%v", entrustJson)
|
|
}
|
|
|
|
// 2、当前最新价格
|
|
var closePrice decimal.Decimal
|
|
switch entrustJson.Order.Type {
|
|
case flags.SpotsMarketType: // 现货
|
|
closePrice, err = GetMoneySpotsPrice(entrustJson.Symbol)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyTransactionCalculationPosition.GetMoneyPrice:%v", common.ErrMoney, err)
|
|
return false, err
|
|
}
|
|
case flags.ContractMarketType: // 合约
|
|
closePrice, err = GetMoneyContractPrice(entrustJson.Symbol)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyTransactionCalculationPosition.GetMoneyPrice:%v", common.ErrMoney, err)
|
|
return false, err
|
|
}
|
|
case flags.ForexMarketType: // 外汇
|
|
closePrice, err = GetMoneyForexPriceNew(entrustJson.Symbol)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyTransactionCalculationPosition.GetMoneyPrice:%v", common.ErrMoney, err)
|
|
return false, err
|
|
}
|
|
}
|
|
if err = Reds.HDel(context.Background(), setting.MarketMoneyPosition, orderId).Err(); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyClosingByOrderId.MarketMoneyPosition.HDel:%v", common.ErrMoney, err)
|
|
return false, flags.ErrCacheDB
|
|
}
|
|
|
|
// 3、平仓处理
|
|
if err = MoneyClosingPosition(ctx, uo.data.mysqlDB, orderId, closePrice.String(), entrustJson.Order, 3); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyClosingByOrderId.MoneyClosingPosition:%v", common.ErrMoney, err)
|
|
return false, flags.ErrCacheDB
|
|
}
|
|
|
|
// 4、平仓更新订阅缓存订单状态
|
|
userSubKey := virtual.OrderIdListKey(setting.MoneySubscribe, entrustJson.UserId)
|
|
if err = UpdateMoneySubscribeHashStatusByOrderId(orderId, userSubKey, flags.Close, flags.SetNull); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyClosingByOrderId.MoneySubscribe:%v", common.ErrMoney, err)
|
|
return false, flags.ErrCacheDB
|
|
}
|
|
|
|
// 5、平仓更新管理员订阅缓存订单状态
|
|
if err = UpdateMoneySubscribeHashStatusByOrderId(orderId, setting.AdminMoneySubscribe, flags.Close, flags.SetNull); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.AdminMoneySubscribe:%v", common.ErrMoney, err)
|
|
return false, flags.ErrCacheDB
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
// UpdateBotMoneyClosingAllByOrderId
|
|
//
|
|
// @Description: 综合(现货|合约|外汇)一键平仓
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param userId
|
|
// @return error
|
|
func (uo *userOrderRepo) UpdateBotMoneyClosingAllByOrderId(ctx context.Context, userId int64) error {
|
|
// 1、查询当前用户所有订单
|
|
orderMap, err := uo.GetBotMoneyTradeByUserId(userId)
|
|
if err != nil {
|
|
applogger.Error("%v UpdateBotMoneyClosingAllByOrderId.GetBotMoneyTradeByUserId:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
|
|
// 2、查询持仓缓存列表数据-1>清理持仓列表缓存 2>处理平仓数据 3>清理订单ID缓存列表
|
|
for _, value := range orderMap {
|
|
var entrust string
|
|
entrust, err = Reds.HGet(context.Background(), setting.MarketMoneyPosition, value).Result()
|
|
if err != nil {
|
|
applogger.Error("%v UpdateBotMoneyClosingAllByOrderId.MarketMoneyPosition.LRange:%v", common.ErrMoney, err)
|
|
return flags.ErrCacheDB
|
|
}
|
|
var entrustJson Moneyd.MoneyTallyCache
|
|
if err = json.Unmarshal([]byte(entrust), &entrustJson); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyClosingAllByOrderId.Unmarshal:%v", common.ErrMoney, err)
|
|
return flags.ErrCacheDB
|
|
}
|
|
|
|
// 获取当前综合(现货|合约|外汇)交易对买一卖一最新报价
|
|
var closePrice decimal.Decimal
|
|
switch entrustJson.Order.Type {
|
|
case flags.SpotsMarketType: // 现货
|
|
closePrice, err = GetMoneySpotsPrice(entrustJson.Symbol)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyTransactionCalculationPosition.GetMoneyPrice:%v", common.ErrMoney, err)
|
|
return err
|
|
}
|
|
case flags.ContractMarketType: // 合约
|
|
closePrice, err = GetMoneyContractPrice(entrustJson.Symbol)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyTransactionCalculationPosition.GetMoneyPrice:%v", common.ErrMoney, err)
|
|
return err
|
|
}
|
|
case flags.ForexMarketType: // 外汇
|
|
closePrice, err = GetMoneyForexPriceNew(entrustJson.Symbol)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyTransactionCalculationPosition.GetMoneyPrice:%v", common.ErrMoney, err)
|
|
return err
|
|
}
|
|
}
|
|
if err = Reds.HDel(context.Background(), setting.MarketMoneyPosition, value).Err(); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyClosingAllByOrderId.MarketMoneyPosition.HDel:%v", common.ErrMoney, err)
|
|
return flags.ErrCacheDB
|
|
}
|
|
|
|
// 平仓
|
|
if err = MoneyClosingPosition(ctx, uo.data.mysqlDB, entrustJson.OrderId, closePrice.String(), entrustJson.Order, 3); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyClosingAllByOrderId.MoneyClosingPosition:%v", common.ErrMoney, err)
|
|
return err
|
|
}
|
|
|
|
// 平仓更新用户订阅订单状态
|
|
userSubKey := virtual.OrderIdListKey(setting.MoneySubscribe, entrustJson.UserId)
|
|
if err = UpdateMoneySubscribeHashStatusByOrderId(entrustJson.OrderId, userSubKey, flags.Close, flags.SetNull); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyClosingAllByOrderId.MoneySubscribe:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
|
|
// 平仓更新管理员订阅订单状态
|
|
if err = UpdateMoneySubscribeHashStatusByOrderId(entrustJson.OrderId, setting.AdminMoneySubscribe, flags.Close, flags.SetNull); err != nil {
|
|
applogger.Error("%v UpdateBotMoneyCancelByOrderId.AdminMoneySubscribe:%v", common.ErrMoney, err)
|
|
return flags.ErrMySqlDB
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// MoneyCreateOneClickRedemption
|
|
//
|
|
// @Description: 现货(开仓|平仓|一键兑换)
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param userId
|
|
// @param order
|
|
// @return string
|
|
// @return error
|
|
func (uo *userOrderRepo) MoneyCreateOneClickRedemption(ctx context.Context, userId int64, order structure.MoneyOrder) (string, error) {
|
|
// 1、下单通知订阅
|
|
stockId := strings.ToLower(order.StockId)
|
|
_, ok := moneyZh.MoneySpotsMapSymbol.Load(stockId)
|
|
if ok {
|
|
go func() {
|
|
moneyZh.MoneySpotsMap <- []byte(stockId)
|
|
}()
|
|
}
|
|
order.StockId = strings.ToUpper(order.StockId)
|
|
|
|
// 交易币市价
|
|
priceNew, err := GetMoneySpotsPrice(stockId)
|
|
if err != nil {
|
|
applogger.Error("%v CreateOneClickRedemption.GetMoneySpotsPrice:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrNetWorkMessage
|
|
}
|
|
|
|
// 2、市价下单记录(1>下单判定 2>订单表 3>资产表[资产|其他交易对])
|
|
order.MarketPrice = priceNew.String()
|
|
orderId, err := uo.MoneyOrdersDealDB(ctx, userId, order)
|
|
if err != nil || len(orderId) == 0 {
|
|
applogger.Error("%v CreateOneClickRedemption.SpotOrdersDealDB:%v", common.ErrSpots, err)
|
|
return flags.SetNull, flags.ErrSpotsMsgThree
|
|
}
|
|
|
|
// 3、市价卖出下单
|
|
switch order.DealType {
|
|
case flags.DealTypeMarket: // 市价下单(市价卖出平仓)
|
|
var openPrice decimal.Decimal
|
|
switch order.TradeType {
|
|
case flags.TradeTypeBuy: // 买入
|
|
case flags.TradeTypeSell: // 卖出
|
|
openPrice = priceNew
|
|
default:
|
|
return flags.SetNull, flags.ErrSpotsMsgFour
|
|
}
|
|
// 市价下单平仓操作-->更新订单表|更新资产表|计算手续费|录入返佣明细|录入交易明细
|
|
if _, err = MoneyOrdersClosingDB(context.Background(), uo.data.mysqlDB, userId, order, orderId, openPrice.String()); err != nil {
|
|
// 一键兑换失败,撤单操作
|
|
_, err = uo.UpdateBotMoneyCancelByOrderId(ctx, orderId)
|
|
if err != nil {
|
|
applogger.Error("%v CreateOneClickRedemption.UpdateBotMoneyCancelByOrderId:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
return flags.SetNull, err
|
|
}
|
|
default:
|
|
return flags.SetNull, flags.ErrSpotMsgOne
|
|
}
|
|
|
|
return orderId, nil
|
|
}
|
|
func (uo *userOrderRepo) MoneyOrdersDealDB(ctx context.Context, userId int64, order structure.MoneyOrder) (string, error) {
|
|
session := uo.data.mysqlDB.NewSession()
|
|
defer session.Close()
|
|
err := session.Begin()
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersDealDB:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 查询当前用户买入或者卖出的可用总资产和冻结总资产
|
|
usableOld, frozenOld, _, err := uo.GetBotUserMoney(session, userId, flags.MoneyUnit)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersDealDB.GetBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 查询当前用户买入或者卖出的可用总资产和冻结总非资产
|
|
var checkCount int
|
|
var usableSymbolOld, frozenSymbolOld decimal.Decimal
|
|
if order.StockId != flags.MoneyUnit {
|
|
usableSymbolOld, frozenSymbolOld, checkCount, err = uo.GetBotUserMoney(session, userId, order.StockId)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersDealDB.GetBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
}
|
|
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("可用资产:%v,冻结资产:%v", userId, frozenOld)
|
|
applogger.Debug("可用非资产:%v,冻结非资产:%v", usableSymbolOld, frozenSymbolOld)
|
|
}
|
|
|
|
// 开仓录入订单表
|
|
checkInt, orderId, err := uo.CreatBotMoneyTradeBySpots(ctx, session, userId, order)
|
|
if err != nil || checkInt <= 0 {
|
|
applogger.Error("%v MoneyOrdersDealDB.CreatBotDigitalTrade:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
orderNumber := decimal.RequireFromString(order.OrderNumber) // 下单数量
|
|
orderMoney := decimal.RequireFromString(order.MarketPrice).Mul(orderNumber) // 下单金额 = 訂單金額 * 訂單數量
|
|
serviceCost := decimal.RequireFromString(order.ServiceCost) // 下单手续费
|
|
totalMoney := orderMoney.Add(serviceCost) // 下单总金额
|
|
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("现货下单金额:%v", orderMoney)
|
|
applogger.Debug("现货下单数量:%v", orderNumber)
|
|
applogger.Debug("现货下单手续费:%v", serviceCost)
|
|
applogger.Debug("现货下单总金额:%v", totalMoney)
|
|
}
|
|
|
|
// 通过交易类型处理下单: 1买入(冻结资产), 2卖出(冻结资产)
|
|
var usableNew, frozenNew, usableNewNo, frozenNewNo decimal.Decimal
|
|
switch order.TradeType {
|
|
case flags.TradeTypeBuy: // 买入
|
|
voteUsaBledOld := usableOld.Cmp(totalMoney)
|
|
voteMix := usableOld.Sub(totalMoney).Div(usableOld).Cmp(utils.DecimalsStrInt())
|
|
if voteUsaBledOld < 0 || voteMix <= 0 {
|
|
return flags.SetNull, flags.ErrSpotsMsgSix
|
|
}
|
|
usableNew = usableOld.Sub(totalMoney) // 可用资产
|
|
frozenNew = frozenOld.Add(totalMoney) // 冻结资产
|
|
|
|
usableNewNo = usableSymbolOld // 非可用资产
|
|
frozenNewNo = frozenSymbolOld // 非冻结资产
|
|
case flags.TradeTypeSell: // 卖出
|
|
if usableSymbolOld.IsZero() || usableSymbolOld.Cmp(orderNumber) < 0 {
|
|
return flags.SetNull, flags.ErrPublicOne
|
|
}
|
|
usableNew = usableOld // 可用资产
|
|
frozenNew = frozenOld // 非可用冻结资产
|
|
|
|
if order.StockId != flags.MoneyUnit {
|
|
usableNewNo = usableSymbolOld // 可用非资产
|
|
frozenNewNo = frozenSymbolOld.Add(orderNumber) // 冻结非资产
|
|
}
|
|
default:
|
|
return flags.SetNull, flags.ErrSpotsMsgSeven
|
|
}
|
|
|
|
// 更新当前下单用户可用资产表
|
|
useMoneyUSD := orders.UpdateBotUserMoneySpots(ctx, usableNew.String(), frozenNew.String())
|
|
checkNum, err := uo.UpdateBotUserMoneySpots(session, userId, flags.MoneyUnit, useMoneyUSD)
|
|
if err != nil || checkNum <= 0 {
|
|
applogger.Error("%v MoneyOrdersDealDB.UpdateBotUserMoneySpots:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 更新非账户资金
|
|
if order.StockId != flags.MoneyUnit {
|
|
if checkCount == 0 {
|
|
userMoneySymbol := orders.BotUserMoneySpots(ctx, userId, usableNewNo.String(), frozenNewNo.String(), order)
|
|
checkInt, err = uo.CreatBotUserMoneySpots(session, userMoneySymbol)
|
|
if err != nil || checkInt <= 0 {
|
|
applogger.Error("%v MoneyOrdersDealDB.CreatBotUserMoneySpots:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
} else {
|
|
userMoney := orders.UpdateBotUserMoneySpots(ctx, usableNewNo.String(), frozenNewNo.String())
|
|
checkNum, err = uo.UpdateBotUserMoneySpots(session, userId, order.StockId, userMoney)
|
|
if err != nil || checkNum <= 0 {
|
|
applogger.Error("%v MoneyOrdersDealDB.UpdateBotUserMoneySpots:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
}
|
|
}
|
|
|
|
err = session.Commit()
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersDealDB:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
return orderId, nil
|
|
}
|
|
func (uo *userOrderRepo) CreatBotMoneyTradeBySpots(ctx context.Context, session *xorm.Session, userId int64, order structure.MoneyOrder) (int64, string, error) {
|
|
var orderId string
|
|
for {
|
|
orderId = orders.CreateRandCodeOrder(10)
|
|
orderList, err := uo.GetBotMoneyTradeByOrderIdSpots(orderId)
|
|
if err != nil || len(orderList) > 0 {
|
|
applogger.Error("%v CreatBotMoneyTrade.GetBotMoneyTradeByOrderIdSpots:%v", err)
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
|
|
botStockTrade := orders.BotMoneyTrade(ctx, userId, orderId, order)
|
|
checkInt, err := session.Table(flags.BotMoneyTrade).Insert(&botStockTrade)
|
|
if err != nil || checkInt < 0 {
|
|
return 0, flags.SetNull, err
|
|
}
|
|
|
|
return checkInt, botStockTrade.OrderId, err
|
|
}
|
|
func (uo *userOrderRepo) GetBotMoneyTradeByOrderIdSpots(orderId string) ([]models.BotMoneyTrade, error) {
|
|
var botMoneyTrade []models.BotMoneyTrade
|
|
if err := uo.data.mysqlDB.Table(flags.BotMoneyTrade).
|
|
Where("order_id = ?", orderId).
|
|
Find(&botMoneyTrade); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return botMoneyTrade, nil
|
|
}
|
|
func (uo *userOrderRepo) UpdateBotUserMoneySpots(session *xorm.Session, userId int64, symbol string, userMoneyUSD models.BotUserMoney) (int64, error) {
|
|
checkNum, err := session.Table(flags.BotUserMoney).
|
|
Where("user_id = ?", userId).
|
|
Where("stock_id = ?", symbol).
|
|
Update(&userMoneyUSD)
|
|
if err != nil {
|
|
return 0, nil
|
|
}
|
|
|
|
return checkNum, nil
|
|
}
|
|
func (uo *userOrderRepo) CreatBotUserMoneySpots(session *xorm.Session, money models.BotUserMoney) (int64, error) {
|
|
checkInt, err := session.Table(flags.BotUserMoney).Insert(&money)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return checkInt, nil
|
|
}
|
|
func MoneyOrdersClosingDB(ctx context.Context, db *xorm.EngineGroup, userId int64, order structure.MoneyOrder, orderId, closingPrice string) (string, error) {
|
|
session := db.NewSession()
|
|
defer session.Close()
|
|
err := session.Begin()
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersClosingDB.NewSession:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 当前用户(买入|卖出)的(可用|冻结)资产
|
|
usableOld, frozenOld, _, err := Uo.GetBotUserMoney(session, userId, flags.MoneyUnit)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersClosingDB.GetBotUserMoney:%v", common.ErrSpots, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 当前用户非(买入|卖出)的(可用|冻结)资产
|
|
var usableNoOld, frozenNoOld decimal.Decimal
|
|
if order.StockId != flags.MoneyUnit {
|
|
usableNoOld, frozenNoOld, _, err = Uo.GetBotUserMoney(session, userId, order.StockId)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersClosingDB.GetBotUserMoney:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("可用资产:%v", usableOld)
|
|
applogger.Debug("冻结资产:%v", frozenOld)
|
|
applogger.Debug("非可用资产:%v", usableNoOld)
|
|
applogger.Debug("非冻结资产:%v", frozenNoOld)
|
|
}
|
|
|
|
// Operational Spot Asset Table
|
|
orderNumber := decimal.RequireFromString(order.OrderNumber) // 订单数量
|
|
orderMoney := orderNumber.Mul(decimal.RequireFromString(order.MarketPrice)) // 订单金额 = (订单数量 * 订单价格)
|
|
serviceCost := decimal.RequireFromString(order.ServiceCost) // 订单手续费
|
|
totalMoney := orderMoney.Add(serviceCost) // 订单总金额 = (订单金额 + 手续费)
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("平仓开仓价格:%v", order.MarketPrice)
|
|
applogger.Debug("平仓金额:%v", orderMoney)
|
|
applogger.Debug("平仓数量:%v", order.OrderNumber)
|
|
applogger.Debug("平仓手续费:%v", serviceCost)
|
|
applogger.Debug("平仓总金额:%v", totalMoney)
|
|
}
|
|
|
|
// (开仓|平仓)价格重新计算:订单金额|手续费|订单总金额
|
|
closePrice := decimal.RequireFromString(closingPrice)
|
|
orderNumberNew := orderMoney.Div(closePrice) // 订单数量 = 下单金额 / 平仓价格
|
|
|
|
// 平仓(手续费处理)
|
|
cost, err := Uo.CalculateHandlingFees(ctx, session, int(userId), flags.SpotsMarketType, int(order.TradeType), orderId, orderMoney.String(), flags.SetOne)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersClosingDB.CalculateHandlingFees:%v", common.ErrMoney, err)
|
|
return flags.SetNull, err
|
|
}
|
|
openOrClosingCost := decimal.RequireFromString(cost)
|
|
totalMoneyPrice := orderNumberNew.Mul(closePrice).Add(openOrClosingCost) // (开仓|平仓)订单总金额 = (开仓|平仓)订单金额 + (开仓|平仓)订单手续费
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("平仓价格:%v", closingPrice)
|
|
applogger.Debug("平仓订单数量:%v", orderNumberNew)
|
|
applogger.Debug("平仓手续费:%v", cost)
|
|
applogger.Debug("平仓总金额:%v", totalMoneyPrice)
|
|
}
|
|
|
|
// 判定是买入还是卖出
|
|
var usableNew, frozenNew, usableNoNew, frozenNoNew decimal.Decimal
|
|
switch order.TradeType {
|
|
case flags.TradeTypeBuy: // 买入
|
|
usableNew = usableOld.Add(totalMoney).Sub(totalMoneyPrice) // 用户总资产
|
|
frozenNew = frozenOld.Sub(totalMoney) // 用户冻结资产
|
|
if order.StockId != flags.MoneyUnit {
|
|
usableNoNew = usableNoOld.Add(orderNumberNew) // 非资产
|
|
frozenNoNew = frozenNoOld // 非冻结资产
|
|
}
|
|
case flags.TradeTypeSell: // 卖出
|
|
usableNew = usableOld.Add(orderMoney).Sub(openOrClosingCost) // 用户可用资产
|
|
frozenNew = frozenOld // 用户冻结资产
|
|
if order.StockId != flags.MoneyUnit {
|
|
if orderNumberNew.Cmp(orderNumber) > 0 {
|
|
orderNumberNew = orderNumber
|
|
}
|
|
usableNoNew = usableNoOld.Sub(orderNumberNew) // 非可用资产
|
|
frozenNoNew = frozenNoOld.Sub(orderNumber) // 非冻结资产
|
|
}
|
|
default:
|
|
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("可用资产:%v", usableNew)
|
|
applogger.Debug("冻结资产:%v", frozenNew)
|
|
applogger.Debug("非可用资产:%v", usableNoNew)
|
|
applogger.Debug("非冻结资产:%v", frozenNoNew)
|
|
}
|
|
|
|
// 更新用户资产信息
|
|
userMoneyUSD := orders.UpdateBotUserMoneySpots(ctx, usableNew.String(), frozenNew.String())
|
|
checkNum, err := Uo.UpdateBotUserMoneySpots(session, userId, flags.MoneyUnit, userMoneyUSD)
|
|
if err != nil || checkNum <= 0 {
|
|
applogger.Error("%v MoneyOrdersClosingDB.UpdateBotUserMoneySpots:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 更新订单信息
|
|
botStockTrade := orders.UpdateBotMoneyStatusByOrderId(ctx, closingPrice, cost, orderMoney.String(), totalMoneyPrice.String(), orderNumberNew.String())
|
|
if err = Uo.UpdateBotMoneyTradeByOrderId(session, orderId, botStockTrade); err != nil {
|
|
applogger.Error("%v MoneyOrdersClosingDB.UpdateBotMoneyTradeByOrderId:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 更新当前用户非的资产信息
|
|
if order.StockId != flags.MoneyUnit {
|
|
userMoneySymbol := orders.UpdateBotUserMoneySpots(ctx, usableNoNew.String(), frozenNoNew.String())
|
|
checkNum, err = Uo.UpdateBotUserMoneySpots(session, userId, order.StockId, userMoneySymbol)
|
|
if err != nil || checkNum <= 0 {
|
|
applogger.Error("%v MoneyOrdersClosingDB.UpdateBotUserMoneySpots:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
}
|
|
|
|
// 返佣记录表|资产表|资金变动表
|
|
err = Uo.MoneyRebateCalculation(ctx, session, int(userId), flags.SpotsMarketType, flags.ClosingPosition, flags.CloseMRebate, cost, orderId)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersClosingDB.MoneyRebateCalculation:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
// 交易明细表(资产|非资产|手续费)
|
|
err = Uo.CreatBotUserMoneyLog(ctx, session, userId, order.TradeType, order.StockId, orderMoney.String(), orderNumberNew.String(), cost, orderId)
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersClosingDB.CreatBotUserMoneyLog:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrSpotMsgTow
|
|
}
|
|
|
|
err = session.Commit()
|
|
if err != nil {
|
|
applogger.Error("%v MoneyOrdersClosingDB.Commit:%v", common.ErrMoney, err)
|
|
return flags.SetNull, flags.ErrMySqlDB
|
|
}
|
|
|
|
return orderId, nil
|
|
}
|
|
|
|
// GetBotMoneyTradeByOrderId
|
|
//
|
|
// @Description:
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param session
|
|
// @param orderId
|
|
// @param status
|
|
// @return *models.BotMoneyTrade
|
|
// @return error
|
|
func (uo *userOrderRepo) GetBotMoneyTradeByOrderId(session *xorm.Session, orderId string, status int) (*models.BotMoneyTrade, error) {
|
|
var botMoneyTrade []models.BotMoneyTrade
|
|
if err := session.Table(flags.BotMoneyTrade).
|
|
Where("order_id = ?", orderId).
|
|
Where("`status` = ?", status).
|
|
Find(&botMoneyTrade); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, value := range botMoneyTrade {
|
|
return &value, nil
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
// GetBotMoneyTradeByUserId
|
|
//
|
|
// @Description:
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param userId
|
|
// @return map[string]string
|
|
// @return error
|
|
func (uo *userOrderRepo) GetBotMoneyTradeByUserId(userId int64) (map[string]string, error) {
|
|
var botMoneyTrade []models.BotMoneyTrade
|
|
if err := uo.data.mysqlDB.Table(flags.BotMoneyTrade).
|
|
Where("user_id = ? ", userId).
|
|
Where("status = 1").
|
|
Find(&botMoneyTrade); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
botMap := make(map[string]string)
|
|
for _, value := range botMoneyTrade {
|
|
botMap[value.OrderId] = value.OrderId
|
|
}
|
|
|
|
return botMap, nil
|
|
}
|
|
|
|
// GetBotUserMoney
|
|
//
|
|
// @Description:
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param session
|
|
// @param userId
|
|
// @param symbol
|
|
// @return decimal.Decimal
|
|
// @return decimal.Decimal
|
|
// @return int
|
|
// @return error
|
|
func (uo *userOrderRepo) GetBotUserMoney(session *xorm.Session, userId int64, symbol string) (decimal.Decimal, decimal.Decimal, int, error) {
|
|
var contractUSDT []models.BotUserMoney
|
|
if err := session.Table(flags.BotUserMoney).
|
|
Where("user_id = ?", userId).
|
|
Where("stock_id = ?", strings.ToUpper(symbol)).
|
|
Find(&contractUSDT); err != nil {
|
|
return decimal.Zero, decimal.Zero, 0, err
|
|
}
|
|
|
|
var usableNum, frozenNum decimal.Decimal
|
|
for _, value := range contractUSDT {
|
|
usableNum = decimal.RequireFromString(value.UsableNum) // 资产可用余额
|
|
frozenNum = decimal.RequireFromString(value.FrozenNum) // 资产冻结数量
|
|
}
|
|
|
|
return usableNum, frozenNum, len(contractUSDT), nil
|
|
}
|
|
|
|
// MoneyVoteDealType
|
|
//
|
|
// @Description:
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param order
|
|
// @return decimal.Decimal
|
|
// @return error
|
|
func (uo *userOrderRepo) MoneyVoteDealType(order structure.MoneyOrder) (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
|
|
}
|
|
|
|
// UpdateMoneyVoteDealType
|
|
//
|
|
// @Description:
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param order
|
|
// @return decimal.Decimal
|
|
// @return error
|
|
func (uo *userOrderRepo) UpdateMoneyVoteDealType(order *models.BotMoneyTrade) (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
|
|
}
|
|
|
|
// UpdateMoneyVoteStopType
|
|
//
|
|
// @Description:
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param order
|
|
// @return bool
|
|
// @return decimal.Decimal
|
|
// @return decimal.Decimal
|
|
// @return error
|
|
func (uo *userOrderRepo) UpdateMoneyVoteStopType(order structure.StopOrder) (bool, decimal.Decimal, decimal.Decimal, error) {
|
|
var checkBool bool
|
|
var stopWinPrice, stopLossPrice decimal.Decimal
|
|
switch order.StopType {
|
|
case flags.StopTypeNone: // 暂无设置止盈止损
|
|
checkBool = false
|
|
case flags.StopTypeSet: // 设置止盈止损
|
|
if len(order.StopWinPrice) != 0 {
|
|
stopWinPrice = decimal.RequireFromString(order.StopWinPrice)
|
|
}
|
|
if len(order.StopLossPrice) != 0 {
|
|
stopLossPrice = decimal.RequireFromString(order.StopLossPrice)
|
|
}
|
|
// 判定设置是否都为零
|
|
if stopWinPrice.IsZero() && stopLossPrice.IsZero() {
|
|
return checkBool, decimal.Decimal{}, decimal.Decimal{}, flags.ErrContractTen
|
|
} else {
|
|
checkBool = true
|
|
}
|
|
default:
|
|
return checkBool, stopWinPrice, stopLossPrice, flags.ErrContractEleven
|
|
}
|
|
|
|
return checkBool, stopWinPrice, stopLossPrice, nil
|
|
}
|
|
|
|
// MoneyVoteTradeType
|
|
//
|
|
// @Description: 股票判定止盈止损配置
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param tradeType
|
|
// @param stopWinPrice
|
|
// @param stopLossPrice
|
|
// @param price
|
|
// @param checkBool
|
|
// @return error
|
|
func (uo *userOrderRepo) MoneyVoteTradeType(tradeType int64, stopWinPrice, stopLossPrice, price decimal.Decimal, checkBool bool) error {
|
|
if checkBool {
|
|
switch tradeType {
|
|
case flags.TradeTypeBuy: // 买涨
|
|
if !stopWinPrice.IsZero() {
|
|
if stopWinPrice.Cmp(price) <= 0 {
|
|
// 限价买涨下单,止盈价格必须大于限价
|
|
return flags.ErrBuyStopWinPrice
|
|
}
|
|
}
|
|
if !stopLossPrice.IsZero() {
|
|
if stopLossPrice.Cmp(price) >= 0 {
|
|
// 限价买涨下单,止损价格必须小于限价
|
|
return flags.ErrBuyStopLossPrice
|
|
}
|
|
}
|
|
case flags.TradeTypeSell: // 买跌
|
|
if !stopWinPrice.IsZero() {
|
|
if stopWinPrice.Cmp(price) >= 0 {
|
|
// 限价买跌下单,止盈价格必须小于限价
|
|
return flags.ErrSellStopWinPrice
|
|
}
|
|
}
|
|
if !stopLossPrice.IsZero() {
|
|
if stopLossPrice.Cmp(price) <= 0 {
|
|
// 限价买跌下单,止损价格必须大于限价
|
|
return flags.ErrSellStopLossPrice
|
|
}
|
|
}
|
|
default:
|
|
return flags.ErrContractTwelve
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// CreatBotUserMoney
|
|
//
|
|
// @Description:
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param session
|
|
// @param digital
|
|
// @return error
|
|
func (uo *userOrderRepo) CreatBotUserMoney(session *xorm.Session, digital models.BotUserMoney) error {
|
|
_, err := session.Table(flags.BotUserMoney).Insert(&digital)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// CreatBotMoneyTrade
|
|
//
|
|
// @Description:
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param session
|
|
// @param trade
|
|
// @return error
|
|
func (uo *userOrderRepo) CreatBotMoneyTrade(session *xorm.Session, trade models.BotMoneyTrade) error {
|
|
_, err := session.Table(flags.BotMoneyTrade).Insert(&trade)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// UpdateBotMoneyTradeByOrderId
|
|
//
|
|
// @Description:
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param session
|
|
// @param orderId
|
|
// @param trade
|
|
// @return error
|
|
func (uo *userOrderRepo) UpdateBotMoneyTradeByOrderId(session *xorm.Session, orderId string, trade models.BotMoneyTrade) error {
|
|
_, err := session.Table(flags.BotMoneyTrade).
|
|
Where("order_id = ?", orderId).
|
|
Update(&trade)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// UpdateBotUserMoney
|
|
//
|
|
// @Description:
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param session
|
|
// @param userId
|
|
// @param symbol
|
|
// @param userMoney
|
|
// @return error
|
|
func (uo *userOrderRepo) UpdateBotUserMoney(session *xorm.Session, userId int64, symbol string, userMoney models.BotUserMoney) error {
|
|
_, err := session.Table(flags.BotUserMoney).
|
|
Where("user_id = ?", userId).
|
|
Where("stock_id = ?", symbol).
|
|
Update(&userMoney)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// VerifyBotMoneyTradeOrderId
|
|
//
|
|
// @Description:
|
|
// @receiver uo
|
|
// @param ctx
|
|
// @param session
|
|
// @return string
|
|
// @return error
|
|
func (uo *userOrderRepo) VerifyBotMoneyTradeOrderId(session *xorm.Session) (string, error) {
|
|
var orderId string
|
|
for {
|
|
orderId = orders.CreateRandCodeOrder(10)
|
|
|
|
var orderList []models.BotMoneyTrade
|
|
err := session.Table(flags.BotMoneyTrade).Where("order_id = ?", orderId).Find(&orderList)
|
|
if err != nil || len(orderList) > 0 {
|
|
applogger.Error("%v VerifyBotMoneyTradeOrderId.Find:%v", common.ErrMoney, err)
|
|
continue
|
|
}
|
|
|
|
break
|
|
}
|
|
|
|
return orderId, nil
|
|
}
|
|
|