This commit is contained in:
2025-03-21 20:44:35 +08:00
parent bac4fd8b11
commit 8cede57a70
21 changed files with 430 additions and 120 deletions

View File

@ -1,6 +1,7 @@
package apis
import (
"errors"
"fmt"
"go-admin/common/const/rediskey"
"go-admin/common/global"
@ -284,7 +285,15 @@ func (e LinePreOrder) AddPreOrder(c *gin.Context) {
return
}
userId := user.GetUserId(c)
if userId <= 0 {
e.Error(500, errors.New("用户不存在"), "用户不存在")
return
}
p := actions.GetPermissionFromContext(c)
req.SetCreateBy(userId)
errs := make([]error, 0)
errStr := make([]string, 0)
var tickerSymbol string
@ -358,6 +367,13 @@ func (e LinePreOrder) BatchAddOrder(c *gin.Context) {
p := actions.GetPermissionFromContext(c)
errs := make([]error, 0)
errStr := make([]string, 0)
userId := user.GetUserId(c)
if userId <= 0 {
e.Error(500, nil, "用户不存在")
return
}
req.SetCreateBy(userId)
s.AddBatchPreOrder(&req, p, &errs)
if len(errs) > 0 {
//e.Logger.Error(err)
@ -392,7 +408,14 @@ func (e LinePreOrder) QuickAddPreOrder(c *gin.Context) {
p := actions.GetPermissionFromContext(c)
errs := make([]error, 0)
errStr := make([]string, 0)
err = s.QuickAddPreOrder(&req, p, &errs)
userId := user.GetUserId(c)
if userId <= 0 {
e.Error(500, nil, "用户不存在")
return
}
err = s.QuickAddPreOrder(&req, p, userId, &errs)
if len(errs) > 0 {
//e.Logger.Error(err)
for _, err2 := range errs {

View File

@ -26,7 +26,6 @@ import (
"github.com/gin-gonic/gin"
"github.com/go-admin-team/go-admin-core/logger"
"github.com/go-admin-team/go-admin-core/sdk/api"
"github.com/shopspring/decimal"
"gorm.io/gorm"
)
@ -364,6 +363,11 @@ func (e LineUserApi) Info(c *gin.Context) {
binanceAccount := service.BinanceAccount{Service: s.Service}
//获取用户资金账户资产
totalAsset, err := binanceAccount.GetTotalAsset(userId)
if err != nil {
e.Logger.Errorf("获取用户资金账户资产失败:%v", err)
}
resp, err := binanceAccount.GetFundingAsset(userId)
if err != nil {
e.Logger.Error(500, err, err.Error())
@ -375,28 +379,26 @@ func (e LineUserApi) Info(c *gin.Context) {
if val != "" {
sonic.Unmarshal([]byte(val), &tickerData)
}
var usdtBalance decimal.Decimal
// var usdtBalance decimal.Decimal
for i, asset := range resp {
symbol := asset.Asset + "USDT"
for _, datum := range tickerData {
if datum.Symbol == symbol {
mul := utility.StringToDecimal(datum.Price).Mul(utility.StringToDecimal(asset.Free))
usdtBalance = usdtBalance.Add(mul)
// mul := utility.StringToDecimal(datum.Price).Mul(utility.StringToDecimal(asset.Free))
// usdtBalance = usdtBalance.Add(mul)
resp[i].UsdtValuation = datum.Price
}
}
//if asset.Asset == "USDT" {
// usdt = asset.Free
//}
}
// 邀请人数
//var inviteNum int64
var inviteNum int64
var userinfo models.LineUser
e.Orm.Model(&models.LineUser{}).Where("id = ?", userId).Find(&userinfo)
e.Orm.Model(&models.LineUser{}).Where("pid =? or top_referrer_id =?", userId, userId).Count(&inviteNum)
var apiUserinfo models.LineApiUser
e.Orm.Model(&models.LineApiUser{}).Where("user_id = ?", userId).Find(&apiUserinfo)
e.Orm.Model(&models.LineApiUser{}).Where("user_id = ? ", userId).Find(&apiUserinfo)
var isAuth bool
if apiUserinfo.ApiKey != "" && apiUserinfo.ApiSecret != "" {
isAuth = true
@ -418,7 +420,7 @@ func (e LineUserApi) Info(c *gin.Context) {
"avatar": userinfo.Avatar,
"user_id": userinfo.Id,
"user_name": userinfo.Nickname,
"invite_num": userinfo.RecommendNum,
"invite_num": inviteNum,
"open_status": apiUserinfo.OpenStatus,
"is_auth": isAuth,
"invite_url": fmt.Sprintf("%s/invice_url?invite_code=%s", ext.ExtConfig.Domain, userinfo.InviteCode),
@ -428,7 +430,7 @@ func (e LineUserApi) Info(c *gin.Context) {
"api_secret": inttostring.EncryptString(apiUserinfo.ApiSecret, 4, 4),
}
returnMap := map[string]interface{}{
"u_balance": usdtBalance.Truncate(2),
"u_balance": totalAsset.Truncate(2),
"margin": userinfo.Money,
"userinfo": user,
"funding_asset": fundingAsset,

View File

@ -9,3 +9,9 @@ type FundingAsset struct {
BtcValuation string `json:"btcValuation"`
UsdtValuation string `json:"usdt_valuation"`
}
type BinanceWalletBalance struct {
Active bool `json:"active"`
Balance string `json:"balance"`
WalletName string `json:"walletName"`
}

View File

@ -3,12 +3,19 @@ package service
import (
"errors"
"fmt"
"github.com/bytedance/sonic"
"github.com/go-admin-team/go-admin-core/sdk/service"
"go-admin/app/admin/models"
"go-admin/common/const/rediskey"
"go-admin/common/global"
"go-admin/common/helper"
ext "go-admin/config"
"go-admin/pkg/utility"
"net/http"
"time"
"github.com/bytedance/sonic"
"github.com/go-admin-team/go-admin-core/logger"
"github.com/go-admin-team/go-admin-core/sdk/service"
"github.com/shopspring/decimal"
)
const ProxyType = "socks5"
@ -62,3 +69,90 @@ func (e *BinanceAccount) GetFundingAsset(userId int) (resp []models.FundingAsset
return resp, nil
}
/*
获取钱包余额
- @param userId 用户id
- @param quoteAsset 币种 USDT, ETH, USDC, BNB等。 默认 BTC
- @return []models.FundingAsset 钱包余额
*/
func (e *BinanceAccount) GetWalletBalance(userId int, quoteAsset string) (resp []models.BinanceWalletBalance, err error) {
if quoteAsset == "" {
quoteAsset = "BTC"
}
var proxyUrl, proxyType string
var apiUser models.LineApiUser
url := "/sapi/v1/asset/wallet/balance"
err = e.Orm.Where(&models.LineApiUser{}).Where("user_id = ?", userId).Find(&apiUser).Error
if err != nil {
e.Log.Errorf("Service LineApiUser error:%s \r\n", err)
return []models.BinanceWalletBalance{}, err
}
if apiUser.Id <= 0 {
e.Log.Errorf("Service LineApiUser error:%s \r\n", "用户未找到")
return []models.BinanceWalletBalance{}, err
}
if ext.ExtConfig.ProxyUrl != "" {
proxyUrl = "127.0.0.1:7890"
proxyType = "http"
}
if apiUser.IpAddress != "" && apiUser.UserPass != "" {
proxyUrl = fmt.Sprintf("%s:%s", apiUser.IpAddress, apiUser.UserPass)
proxyType = ProxyType
}
clinet, err := helper.NewBinanceClient(apiUser.ApiKey, apiUser.ApiSecret, proxyType, proxyUrl)
if err != nil {
e.Log.Errorf("Service NewBinanceClient error:%s \r\n", err)
return []models.BinanceWalletBalance{}, err
}
req := map[string]string{
"quoteAsset": quoteAsset,
"recvWindow": "10000",
}
httpResp, statusCode, err := clinet.SendSpotAuth(url, "GET", req)
if err != nil {
e.Log.Errorf("Service SendSpotAuth error:%s \r\n", err)
return []models.BinanceWalletBalance{}, err
}
if statusCode != http.StatusOK {
e.Log.Errorf("Service 请求失败 error:%s \r\n", err)
return []models.BinanceWalletBalance{}, errors.New("请求失败")
}
sonic.Unmarshal(httpResp, &resp)
return resp, nil
}
/*
获取用户总资产
*/
func (e *BinanceAccount) GetTotalAsset(userId int) (decimal.Decimal, error) {
key := fmt.Sprintf(rediskey.User_Total_Asset, global.EXCHANGE_BINANCE, userId)
totalStr, _ := helper.DefaultRedis.GetString(key)
result := decimal.Zero
if totalStr != "" {
result = utility.StrToDecimal(totalStr)
} else {
assets, err := e.GetWalletBalance(userId, "USDT")
if err != nil {
logger.Errorf("GetTotalAsset error:%s", err)
return decimal.Decimal{}, err
}
for _, asset := range assets {
result = result.Add(utility.StrToDecimal(asset.Balance))
}
helper.DefaultRedis.SetStringExpire(key, result.String(), 30*time.Second)
}
return result, nil
}

View File

@ -209,6 +209,7 @@ type LineAddPreOrderReq struct {
ReduceReTakeProfitRatio decimal.Decimal `json:"re_take_profit_ratio" comment:"减仓后亏损回本止盈百分比"`
Ext []LineAddPreOrderExtReq `json:"ext" ` //拓展字段
common.ControlBy
}
type LinePreOrderAddPositionReq struct {
@ -389,6 +390,7 @@ type LineBatchAddPreOrderReq struct {
ReduceTakeProfitRatio decimal.Decimal `json:"reduce_take_profit"` //主单减仓后止盈价百分比
ReduceStopLossRatio decimal.Decimal `json:"reduce_stop_price"` //主单减仓后止损价百分比
Ext []LineAddPreOrderExtReq `json:"ext"` //拓展字段
common.ControlBy
}
func (req LineBatchAddPreOrderReq) CheckParams() error {

View File

@ -18,10 +18,12 @@ type LineSymbolGetPageReq struct {
}
type LineSymbolExportResp struct {
Symbol string `json:"symbol" excel:"交易"`
Coin string `json:"coin" excel:"基础货币"`
Currency string `json:"currency" excel:"计价货币"`
SymbolType string `json:"symbolType" excel:"交易对类型"`
ExchangeType string `json:"exchangeType" excel:"交易"`
Symbol string `json:"symbol" excel:"交易对"`
Coin string `json:"coin" excel:"基础货币"`
Currency string `json:"currency" excel:"计价货币"`
SymbolType string `json:"symbolType" excel:"交易对类型"`
LastPrice string `json:"lastPrice" excel:"最新价"`
}
type LineSymbolOrder struct {

View File

@ -278,14 +278,15 @@ func (receiver FrontedLoginReq) CheckParams() int {
}
type AddApiKeyReq struct {
ApiName string `json:"api_name"`
ApiKey string `json:"api_key"`
ApiSecret string `json:"api_secret"`
ApiIp string `json:"api_ip"`
ExchangeType string `json:"exchange_type"`
ApiName string `json:"api_name"`
ApiKey string `json:"api_key"`
ApiSecret string `json:"api_secret"`
ApiIp string `json:"api_ip"`
}
func (a AddApiKeyReq) CheckParams() int {
if a.ApiKey == "" || a.ApiSecret == "" {
if a.ExchangeType == "" || a.ApiKey == "" || a.ApiSecret == "" {
return statuscode.ParamErr
}
return statuscode.OK

View File

@ -29,7 +29,7 @@ func (e *LineDirection) GetPage(c *dto.LineDirectionGetPageReq, p *actions.DataP
Scopes(
cDto.MakeCondition(c.GetNeedSearch()),
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
actions.Permission(data.TableName(), p),
// actions.Permission(data.TableName(), p),
).
Find(list).Limit(-1).Offset(-1).
Count(count).Error
@ -45,9 +45,9 @@ func (e *LineDirection) Get(d *dto.LineDirectionGetReq, p *actions.DataPermissio
var data models.LineDirection
err := e.Orm.Model(&data).
Scopes(
actions.Permission(data.TableName(), p),
).
// Scopes(
// actions.Permission(data.TableName(), p),
// ).
First(model, d.GetId()).Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
err = errors.New("查看对象不存在或无权查看")

View File

@ -391,6 +391,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
Type: 1,
Switch: "0",
}
saveTemplateParams.CreateBy = req.CreateBy
e.Orm.Model(&models.LineOrderTemplateLogs{}).Create(&saveTemplateParams)
}
if req.SaveTemplate == "2" {
@ -426,6 +427,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
continue
}
AddOrder.CreateBy = req.CreateBy
AddOrder.ExchangeType = req.ExchangeType
AddOrder.OrderCategory = 1
AddOrder.SignPriceType = "new"
@ -598,6 +600,7 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
ext.TotalBefore = mainParam.RemainingQuantity //初始数量
ext.TotalAfter = calculateResp.RemainingQuantity //计算后数量
ext.ReTakeRatio = calculateResp.Ratio
ext.CreateBy = req.CreateBy
mainParam.LossBeginPercent = addPosition.PriceRatio
mainParam.RemainingQuantity = calculateResp.RemainingQuantity
mainParam.TotalLossAmountU = calculateResp.TotalLossAmountU
@ -637,18 +640,29 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
//是否有止盈止损订单
if req.Profit != "" {
if strings.ToUpper(req.Site) == "BUY" {
profitOrder.Site = "SELL"
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
if req.PricePattern == "mixture" {
mixturePrice := utility.StrToDecimal(req.Profit)
if mixturePrice.Cmp(decimal.Zero) <= 0 {
return fmt.Errorf("止盈价不能小于等于0")
}
profitOrder.Price = mixturePrice.Truncate(int32(tradeSet.PriceDigit)).String()
profitOrder.Rate = "0"
} else {
profitOrder.Site = "BUY"
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
if strings.ToUpper(req.Site) == "BUY" {
profitOrder.Site = "SELL"
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 + utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
} else {
profitOrder.Site = "BUY"
profitOrder.Price = decimal.NewFromFloat(utility.StringToFloat64(AddOrder.Price) * (1 - utility.StringToFloat64(req.Profit)/100)).Truncate(int32(tradeSet.PriceDigit)).String()
}
profitOrder.Rate = req.Profit
}
profitOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
profitOrder.Pid = AddOrder.Id
profitOrder.OrderType = 1
profitOrder.Status = 0
profitOrder.Rate = req.Profit
profitOrder.MainId = AddOrder.Id
if req.ProfitNumRatio.Cmp(decimal.Zero) > 0 {
@ -673,12 +687,23 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
}
if req.ReducePriceRatio.Cmp(decimal.Zero) > 0 {
if strings.ToUpper(req.Site) == "BUY" {
stopOrder.Site = "SELL"
stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Sub(utility.SafeDiv(req.ReducePriceRatio, decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
if req.PricePattern == "mixture" {
if req.ReducePriceRatio.Cmp(decimal.Zero) <= 0 {
return errors.New("检查价格不能小于等于0")
}
stopOrder.Price = req.ReducePriceRatio.Truncate(int32(tradeSet.PriceDigit)).String()
stopOrder.Rate = "0"
} else {
stopOrder.Site = "BUY"
stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Add(utility.SafeDiv(req.ReducePriceRatio, decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
if strings.ToUpper(req.Site) == "BUY" {
stopOrder.Site = "SELL"
stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Sub(utility.SafeDiv(req.ReducePriceRatio, decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
} else {
stopOrder.Site = "BUY"
stopOrder.Price = utility.StrToDecimal(AddOrder.Price).Mul(decimal.NewFromInt(1).Add(utility.SafeDiv(req.ReducePriceRatio, decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()
}
stopOrder.Rate = req.ReducePriceRatio.String()
}
stopOrder.OrderSn = strconv.FormatInt(snowflakehelper.GetOrderId(), 10)
stopOrder.Pid = AddOrder.Id
@ -686,7 +711,6 @@ func (e *LinePreOrder) AddPreOrder(req *dto.LineAddPreOrderReq, p *actions.DataP
stopOrder.OrderType = 4
stopOrder.Status = 0
stopOrder.BuyPrice = "0"
stopOrder.Rate = req.ReducePriceRatio.String()
stopNum := utility.StrToDecimal(AddOrder.Num).Mul(req.ReduceNumRatio.Div(decimal.NewFromInt(100)).Truncate(4))
stopOrder.Num = stopNum.Truncate(int32(tradeSet.AmountDigit)).String()
stopOrder.ExpireTime = time.Now().AddDate(10, 0, 0)
@ -1068,6 +1092,8 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p
Type: 2,
Switch: "0",
}
saveTemplateParams.CreateBy = p.UserId
e.Orm.Model(&models.LineOrderTemplateLogs{}).Create(&saveTemplateParams)
}
@ -1149,6 +1175,7 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p
req.ReduceNumRatio = batchReq.ReduceNumRatio
req.ReduceStopLossRatio = batchReq.ReduceStopLossRatio
req.ReduceTakeProfitRatio = batchReq.ReduceTakeProfitRatio
req.CreateBy = batchReq.CreateBy
e.AddPreOrder(&req, p, errs, tickerSymbol)
}
@ -1162,7 +1189,7 @@ func (e *LinePreOrder) AddBatchPreOrder(batchReq *dto.LineBatchAddPreOrderReq, p
}
// QuickAddPreOrder 模板快速下单
func (e *LinePreOrder) QuickAddPreOrder(quickReq *dto.QuickAddPreOrderReq, p *actions.DataPermission, errs *[]error) error {
func (e *LinePreOrder) QuickAddPreOrder(quickReq *dto.QuickAddPreOrderReq, p *actions.DataPermission, userId int, errs *[]error) error {
templateLogs := make([]models.LineOrderTemplateLogs, 0)
e.Orm.Model(&models.LineOrderTemplateLogs{}).Where("id in ?", strings.Split(quickReq.Ids, ",")).Find(&templateLogs)
for _, log := range templateLogs {
@ -1188,6 +1215,13 @@ func (e *LinePreOrder) QuickAddPreOrder(quickReq *dto.QuickAddPreOrderReq, p *ac
if log.Type == 2 {
var batchAddPreOrder dto.LineBatchAddPreOrderReq
sonic.Unmarshal([]byte(log.Params), &batchAddPreOrder)
if userId > 0 {
batchAddPreOrder.CreateBy = userId
} else {
batchAddPreOrder.CreateBy = log.CreateBy
}
e.AddBatchPreOrder(&batchAddPreOrder, p, errs)
}
}

View File

@ -20,6 +20,7 @@ import (
"go-admin/common/global"
"go-admin/common/helper"
commonModels "go-admin/models"
models2 "go-admin/models"
"go-admin/pkg/utility"
"go-admin/services/binanceservice"
)
@ -37,7 +38,7 @@ func (e *LineSymbol) GetPage(c *dto.LineSymbolGetPageReq, p *actions.DataPermiss
Scopes(
cDto.MakeCondition(c.GetNeedSearch()),
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
actions.Permission(data.TableName(), p),
// actions.Permission(data.TableName(), p),
).
Find(list).Limit(-1).Offset(-1).
Count(count).Error
@ -126,7 +127,7 @@ func (e *LineSymbol) ExportExcel(c *gin.Context, p *actions.DataPermission, req
err := e.Orm.Model(&data).
Scopes(
cDto.MakeCondition(req.GetNeedSearch()),
actions.Permission(data.TableName(), p),
// actions.Permission(data.TableName(), p),
).
Find(&list).Error
@ -134,17 +135,64 @@ func (e *LineSymbol) ExportExcel(c *gin.Context, p *actions.DataPermission, req
return err
}
exchanges := []string{}
exchangeFutMap := make(map[string]models2.TradeSet)
exchangeSpotMap := make(map[string]models2.TradeSet)
for _, v := range list {
if !utility.ContainsStr(exchanges, v.ExchangeType) {
key := fmt.Sprintf(global.TICKER_FUTURES, v.ExchangeType, "*")
key2 := fmt.Sprintf(global.TICKER_SPOT, v.ExchangeType, "*")
futs, _ := helper.DefaultRedis.GetAllKeysAndValues(key)
spots, _ := helper.DefaultRedis.GetAllKeysAndValues(key2)
trade := models2.TradeSet{}
for _, v2 := range futs {
if v2 != "" {
sonic.Unmarshal([]byte(v2), &trade)
if trade.LastPrice != "" {
exchangeFutMap[v.ExchangeType+"_"+trade.Coin+trade.Currency] = trade
}
}
}
for _, v2 := range spots {
if v2 != "" {
sonic.Unmarshal([]byte(v2), &trade)
if trade.LastPrice != "" {
exchangeSpotMap[v.ExchangeType+"_"+trade.Coin+trade.Currency] = trade
}
}
}
exchanges = append(exchanges, v.ExchangeType)
}
}
for _, v := range list {
item := dto.LineSymbolExportResp{
Symbol: v.Symbol,
Coin: v.BaseAsset,
Currency: v.QuoteAsset,
ExchangeType: v.ExchangeType,
Symbol: v.Symbol,
Coin: v.BaseAsset,
Currency: v.QuoteAsset,
}
if v.Type == "1" {
item.SymbolType = "现货"
if v, ok := exchangeSpotMap[v.ExchangeType+"_"+v.Symbol]; ok {
if v.LastPrice != "" {
item.LastPrice = v.LastPrice
}
}
} else {
item.SymbolType = "合约"
if v, ok := exchangeFutMap[v.ExchangeType+"_"+v.Symbol]; ok {
if v.LastPrice != "" {
item.LastPrice = v.LastPrice
}
}
}
datas = append(datas, item)

View File

@ -51,7 +51,7 @@ func (e *LineUser) GetPage(c *dto.LineUserGetPageReq, p *actions.DataPermission,
Scopes(
cDto.MakeCondition(c.GetNeedSearch()),
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
actions.Permission(data.TableName(), p),
// actions.Permission(data.TableName(), p),
).
Find(list).Limit(-1).Offset(-1).
Count(count).Error
@ -225,15 +225,16 @@ func (e *LineUser) AddApiKey(userId int, req *dto.AddApiKeyReq) int {
}
err = e.Orm.Model(&models.LineApiUser{}).Create(&models.LineApiUser{
UserId: int64(userId),
ApiName: req.ApiName,
ApiKey: req.ApiKey,
ApiSecret: req.ApiSecret,
Affiliation: 3,
AdminShow: 0,
Site: "3",
Subordinate: "0",
OpenStatus: 0,
ExchangeType: req.ExchangeType,
UserId: int64(userId),
ApiName: req.ApiName,
ApiKey: req.ApiKey,
ApiSecret: req.ApiSecret,
Affiliation: 3,
AdminShow: 0,
Site: "3",
Subordinate: "0",
OpenStatus: 0,
}).Error
if err != nil {
@ -743,6 +744,8 @@ func (e *LineUser) OpenStatus(req *dto.OpenStatusReq, userId int) int {
propperty := dto.LineUserPropertyResp{}
e.GetProperty(userId, &propperty)
logger.Infof("合约可用资产:%v", propperty.FuturesFreeAmount)
logger.Infof("现货可用资产:%v", propperty.SpotFreeAmount)
//可用资产不足
if propperty.FuturesFreeAmount.Cmp(userSet.MinOrderAmount) < 0 && propperty.SpotFreeAmount.Cmp(userSet.MinOrderAmount) < 0 {
return statuscode.PropertyInsufficient

View File

@ -142,7 +142,7 @@ func (t AutoPlaceOrder) Exec(arg interface{}) error {
preOrderService.Orm = db
errs := make([]error, 0)
errStr := make([]string, 0)
err := preOrderService.QuickAddPreOrder(&req, nil, &errs)
err := preOrderService.QuickAddPreOrder(&req, nil, 0, &errs)
if err != nil {
return err
}

View File

@ -0,0 +1,6 @@
package rediskey
const (
//用户总资产 {exchange_type,user_id}
User_Total_Asset = "u_total_asset:%s:%v"
)

View File

@ -8,6 +8,7 @@ import (
"net/http"
"net/url"
"strings"
"time"
"golang.org/x/net/proxy"
)
@ -20,7 +21,9 @@ import (
*/
func CreateHtppProxy(proxyType, proxyAddr string, client *http.Client) error {
// Set up proxy based on type (HTTP, HTTPS, SOCKS5)
transport := &http.Transport{}
transport := &http.Transport{
TLSHandshakeTimeout: 10 * time.Second,
}
if proxyAddr != "" {
if !strings.HasPrefix(proxyAddr, "http://") && !strings.HasPrefix(proxyAddr, "https://") && !strings.HasPrefix(proxyAddr, "socks5://") {
proxyAddr = proxyType + "://" + proxyAddr

View File

@ -1,18 +1,13 @@
package authservice
import (
"bytes"
"fmt"
"go-admin/common/const/rediskey"
"go-admin/common/helper"
statuscode "go-admin/common/status_code"
ext "go-admin/config"
"go-admin/pkg/cryptohelper/inttostring"
"io/ioutil"
"net/http"
"time"
"github.com/bytedance/sonic"
log "github.com/go-admin-team/go-admin-core/logger"
"go.uber.org/zap"
)
@ -496,60 +491,8 @@ func SendGoToneSms(phone, area string, smsType int) int {
}
//ext.ExtConfig.GoToneSmsConfig
// SmsRequest 用于构建发送短信请求的结构体
type SmsRequest struct {
Recipient string `json:"recipient"` // 收件人电话号码
Message string `json:"message"` // 短信内容
SenderId string `json:"sender_id"` // 发送者名称
Type string `json:"type"`
}
// 创建请求数据
smsRequest := SmsRequest{
Recipient: "+" + area + phone,
SenderId: ext.ExtConfig.GoToneSmsConfig.SenderId,
Message: fmt.Sprintf("欢迎使用 GoTone SMS高速稳定地发送短信至中国大陆及全球用户体验验证码%s。如非本人操作请忽略此信息", smsString),
Type: "plain",
}
// 将请求数据编码为 JSON
requestBody, err := sonic.Marshal(smsRequest)
if err != nil {
log.Error("GoToneSms requestBody Error:", err)
return statuscode.ServerError
}
// 创建 HTTP 请求
req, err := http.NewRequest("POST", ext.ExtConfig.GoToneSmsConfig.APIEndpoint, bytes.NewBuffer(requestBody))
if err != nil {
log.Error("GoToneSms http.NewRequest Error:", err)
return statuscode.ServerError
}
// 设置请求头
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+ext.ExtConfig.GoToneSmsConfig.Authorization) // 使用 API 密钥进行身份验证
// todo 短信cangchu
// 创建 HTTP 客户端并发送请求
client := &http.Client{
Timeout: 10 * time.Second, // 设置请求超时时间
}
resp, err := client.Do(req)
fmt.Println("resp:", resp)
if err != nil {
log.Error("GoToneSms do NewRequest Error:", err)
return statuscode.CaptchaFailInSend
}
defer resp.Body.Close()
// 检查响应状态
if resp.StatusCode != http.StatusOK {
log.Error("GoToneSms do NewRequest Error:", err)
return statuscode.CaptchaFailInSend
}
// 读取响应体
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("读取响应体失败:", err)
fmt.Printf("响应体: %s", string(body))
return statuscode.CaptchaFailInSend
//return fmt.Errorf("读取响应体失败: %v", err)
}
// 打印响应内容(调试用)
//记录短信发送操作
helper.DefaultRedis.SetStringExpire(registerKey, "1", time.Second*60)

View File

@ -16,11 +16,11 @@ type Extend struct {
EmailConfig EmailConfig `mapstructure:"emailConfig"`
BinanceSet BinanceConfig `mapstructure:"binanceSet"` //binance配置
Domain string //网站域名
GoToneSmsConfig GoToneSmsConfig `mapstructure:"GoToneSmsConfig"`
UDunConfig UDunConfig `mapstructure:"UDunConfig"`
ProxyUrl string //代理地址
CoinGate CoinGateConfig `mapstructure:"coingate"` //coingate钱包
GoToneSmsConfig GoToneSmsConfig `mapstructure:"GoToneSmsConfig"`
InnoPaas InnoPaasConfig `mapstructure:"innoPaas"` //创蓝短信
}
type CoinGateConfig struct {
@ -70,6 +70,12 @@ type GoToneSmsConfig struct {
Authorization string `json:"authorization"`
}
type InnoPaasConfig struct {
Url string `json:"url"`
ApiKey string `json:"apiKey"`
Password string `json:"password"`
}
type UDunConfig struct {
UDunUrl string `json:"UDunUrl"`
UDunMerchantID string `json:"UDunMerchantID"`

View File

@ -11,7 +11,7 @@ settings:
readtimeout: 1
writertimeout: 2
# 数据权限功能开关
enabledp: false
enabledp: true
logger:
# 日志存放路径
path: temp/logs
@ -82,6 +82,10 @@ settings:
sender_id: "GoTone SMS"
api_endpoint: "https://gosms.one/api/v3/sms/send"
authorization: "CVZgh3iIAQpJuvaakQmxOo9q2uOb7Veqs7ls5KIX263d87ee"
InnoPaas:
url: "http://intapi.sgap.253.com"
apiKey: "OI1706483"
password: "N4R84hhVvP6505"
#UDun 配置
UDunConfig:

View File

@ -739,7 +739,7 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd
for _, order := range orders {
order.Num = num.String()
if fist && order.OrderCategory == 1 && order.OrderType == 1 && orderExt.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && orderExt.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 {
if fist && (order.OrderCategory == 3 || order.OrderCategory == 1) && order.OrderType == 1 && orderExt.TakeProfitNumRatio.Cmp(decimal.Zero) > 0 && orderExt.TakeProfitNumRatio.Cmp(decimal.NewFromInt(100)) != 0 {
//主单第一次且止盈数量不是100% 止盈数量
order.Num = num.Mul(orderExt.TakeProfitNumRatio.Div(decimal.NewFromInt(100))).Truncate(int32(tradeSet.AmountDigit)).String()
}
@ -761,7 +761,7 @@ func processTakeProfitAndStopLossOrders(db *gorm.DB, preOrder *models.LinePreOrd
order.Rate = percentag.String()
percentag = percentag.Div(decimal.NewFromInt(100))
order.Price = price.Mul(decimal.NewFromInt(1).Add(percentag)).Truncate(int32(tradeSet.PriceDigit)).String()
} else if orderExt.Id > 0 {
} else if !fist && orderExt.TpTpPriceRatio.Cmp(decimal.Zero) > 0 {
percentag := orderExt.TpTpPriceRatio
order.Rate = percentag.String()
order.Price = price.Mul(decimal.NewFromInt(1).Add(percentag.Div(decimal.NewFromInt(100)))).Truncate(int32(tradeSet.PriceDigit)).String()

View File

@ -0,0 +1,76 @@
package smsservice
import (
"bytes"
"fmt"
statuscode "go-admin/common/status_code"
"go-admin/config"
"io/ioutil"
"net/http"
"time"
"github.com/bytedance/sonic"
"github.com/go-admin-team/go-admin-core/logger"
)
type GotoneService struct {
}
func (s *GotoneService) SendSMS(area, phonenumber string, content string) int {
type SmsRequest struct {
Recipient string `json:"recipient"` // 收件人电话号码
Message string `json:"message"` // 短信内容
SenderId string `json:"sender_id"` // 发送者名称
Type string `json:"type"`
}
// 创建请求数据
smsRequest := SmsRequest{
Recipient: "+" + area + phonenumber,
SenderId: config.ExtConfig.GoToneSmsConfig.SenderId,
Message: fmt.Sprintf("欢迎使用 GoTone SMS高速稳定地发送短信至中国大陆及全球用户体验验证码%s。如非本人操作请忽略此信息", content),
Type: "plain",
}
// 将请求数据编码为 JSON
requestBody, err := sonic.Marshal(smsRequest)
if err != nil {
logger.Error("GoToneSms requestBody Error:", err)
return statuscode.ServerError
}
// 创建 HTTP 请求
req, err := http.NewRequest("POST", config.ExtConfig.GoToneSmsConfig.APIEndpoint, bytes.NewBuffer(requestBody))
if err != nil {
logger.Error("GoToneSms http.NewRequest Error:", err)
return statuscode.ServerError
}
// 设置请求头
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+config.ExtConfig.GoToneSmsConfig.Authorization) // 使用 API 密钥进行身份验证
// 创建 HTTP 客户端并发送请求
client := &http.Client{
Timeout: 10 * time.Second, // 设置请求超时时间
}
resp, err := client.Do(req)
fmt.Println("resp:", resp)
if err != nil {
logger.Error("GoToneSms do NewRequest Error:", err)
return statuscode.CaptchaFailInSend
}
defer resp.Body.Close()
// 检查响应状态
if resp.StatusCode != http.StatusOK {
logger.Error("GoToneSms do NewRequest Error:", err)
return statuscode.CaptchaFailInSend
}
// 读取响应体
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
logger.Error("读取响应体失败:", err)
fmt.Printf("响应体: %s", string(body))
return statuscode.CaptchaFailInSend
//return fmt.Errorf("读取响应体失败: %v", err)
}
return statuscode.OK
}

View File

@ -0,0 +1,44 @@
package smsservice
import (
"fmt"
statuscode "go-admin/common/status_code"
"go-admin/config"
"io"
"net/http"
"strings"
"github.com/bytedance/sonic"
"github.com/go-admin-team/go-admin-core/logger"
)
type InnopaasService struct {
}
func (i *InnopaasService) SendSMS(area, phoneNumber string, message string) int {
// Implement the logic to send SMS using Innopass API
params := map[string]string{
"account": config.ExtConfig.InnoPaas.ApiKey,
"password": config.ExtConfig.InnoPaas.Password,
"mobile": area + phoneNumber,
"msg": message,
}
payload, _ := sonic.MarshalString(params) // strings.NewReader("{\"account\":\"I7145744\",\"password\":\"password\",\"mobile\":\"0012012074149,0012012074142\",\"msg\":\"Your verification code is 8888\"}")
req, _ := http.NewRequest("POST", config.ExtConfig.InnoPaas.Url, strings.NewReader(payload))
req.Header.Add("accept", "application/json")
req.Header.Add("content-type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
logger.Error("读取响应体失败:", err)
fmt.Printf("响应体: %s", string(body))
return statuscode.CaptchaFailInSend
//return fmt.Errorf("读取响应体失败: %v", err)
}
return statuscode.OK
}

View File

@ -0,0 +1,13 @@
package smsservice
type SMSService interface {
// SendSMS 发送短信
// area 区号
// phoneNumber 手机号
// message 短信内容
SendSMS(area, phoneNumber string, message string) int
}
func NewSMSService() SMSService {
return &GotoneService{}
}