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.
1248 lines
41 KiB
1248 lines
41 KiB
package data
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/shopspring/decimal"
|
|
"matchmaking-system/internal/biz/structure"
|
|
"matchmaking-system/internal/data/memory"
|
|
"matchmaking-system/internal/data/mq/consumer"
|
|
"matchmaking-system/internal/data/socket/publicData"
|
|
"matchmaking-system/internal/data/socket/shareData"
|
|
"matchmaking-system/internal/data/tradedeal/share"
|
|
"matchmaking-system/internal/data/tradedeal/virtual"
|
|
"matchmaking-system/internal/pkg/flags"
|
|
"matchmaking-system/internal/pkg/logging/applogger"
|
|
"matchmaking-system/internal/pkg/logging/common"
|
|
"matchmaking-system/internal/pkg/setting"
|
|
"matchmaking-system/internal/pkg/utils"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
/*
|
|
印度股行情订阅
|
|
1、接收用户印度股下单的交易对印度股行情
|
|
2、将订阅行情写入内存中用于并发计算
|
|
3、挂单(市价|限价)缓存队列处理-开仓
|
|
4、持仓缓存队列处理-平仓
|
|
*/
|
|
|
|
// ShareInrMessage
|
|
// @Description:
|
|
type ShareInrMessage struct {
|
|
Symbol string `json:"symbol,omitempty"` // 交易所:股票代码
|
|
StockCode string `json:"stock_code,omitempty"` // 股票代码
|
|
StockName string `json:"stock_name,omitempty"` // 股票名,可能为空
|
|
Price decimal.Decimal `json:"price,omitempty"` // 实时价格
|
|
UpDownRate decimal.Decimal `json:"up_down_rate,omitempty"` // 涨跌%
|
|
UpDown decimal.Decimal `json:"up_down,omitempty"` // 涨跌额
|
|
TradeV decimal.Decimal `json:"trade_v,omitempty"` // 技术评级指标值
|
|
TradeK string `json:"trade_k,omitempty"` // 技术评级
|
|
Vol int64 `json:"vol,omitempty"` // 成交量
|
|
TurnoverPriceTotal decimal.Decimal `json:"turnover_price_total,omitempty"` // 成交量*价格
|
|
PriceTotal string `json:"price_total,omitempty"` // 总市值
|
|
PE string `json:"p_e,omitempty"` // pe
|
|
Eps string `json:"eps,omitempty"` // EPS
|
|
EmployeesNumber string `json:"employees_number,omitempty"` // 雇员
|
|
Plate string `json:"plate,omitempty"` // 板块
|
|
Desc string `json:"desc,omitempty"` // 描述
|
|
PriceCode string `json:"price_code,omitempty"` // 价格类型
|
|
Country string `json:"country,omitempty"` // 国家
|
|
Ts int64 `json:"ts,omitempty"` // 时间
|
|
Token string `json:"token,omitempty"` // Token 令牌
|
|
}
|
|
|
|
// ShareInrSymbol
|
|
// @Description:
|
|
type ShareInrSymbol struct {
|
|
InrMap chan []byte // 订单交易对 -- 用户下单通知订阅
|
|
InrSetMap chan []byte // 订单交易对 -- 用户盘前|盘后行情订阅
|
|
InrMapSymbol sync.Map // 订阅交易簿 -- 过滤重复
|
|
InrSetMapSymbol sync.Map // 订阅交易簿 -- 过滤重复
|
|
}
|
|
|
|
// InitCacheSymbolShareInr
|
|
//
|
|
// @Description:
|
|
// @param ctx
|
|
// @param uo
|
|
func InitCacheSymbolShareInr(ctx context.Context, uo *Data) {
|
|
for {
|
|
thaList, err := GetBotStockInListByStockId(ctx, uo)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for _, value := range thaList {
|
|
// Write to the redis list hot cache for initializing subscriptions when the program is pulled up
|
|
checkBool, err := uo.redisDB.HExists(context.Background(), setting.MarketShareInr, value).Result()
|
|
if err != nil {
|
|
applogger.Error("%v InitCacheSymbolShareInr.MarketShareInr.HExists:%v", common.ErrShareInr, err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
if !checkBool {
|
|
if err := uo.redisDB.HSet(context.Background(), setting.MarketShareInr, value, value).Err(); err != nil {
|
|
applogger.Error("%v InitCacheSymbolShareInr.MarketShareInr.HSet:%v", common.ErrShareInr, err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Info("初始化印度股股票代码:%v", value)
|
|
}
|
|
}
|
|
|
|
time.Sleep(10 * time.Second)
|
|
}
|
|
}
|
|
|
|
// InitSubscribeShareInr
|
|
//
|
|
// @Description: 状态机加载订阅
|
|
// @param ctx
|
|
// @param uo
|
|
// @param shareTha
|
|
func InitSubscribeShareInr(shareInr *ShareInrSymbol, check bool) {
|
|
for {
|
|
var key string
|
|
if check {
|
|
key = setting.MarketShareBlkInr
|
|
} else {
|
|
key = setting.MarketShareInr
|
|
}
|
|
|
|
listSpots, err := LoadLRangeList(key)
|
|
if err != nil {
|
|
applogger.Error("%v InitSubscribeShareInr.LoadLRangeList:%v", common.ErrShareInr, err)
|
|
return
|
|
}
|
|
|
|
for _, value := range listSpots {
|
|
// Handling duplicate subscriptions
|
|
_, ok := shareInr.InrMapSymbol.Load(value)
|
|
if ok {
|
|
continue
|
|
}
|
|
|
|
shareInr.InrMap <- []byte(value)
|
|
}
|
|
|
|
time.Sleep(10 * time.Second)
|
|
}
|
|
}
|
|
|
|
// InitShareInrCloseCachePrice
|
|
//
|
|
// @Description:
|
|
// @param shareInr
|
|
// @param check
|
|
func InitShareInrCloseCachePrice(check bool) {
|
|
for {
|
|
var key string
|
|
if check {
|
|
key = setting.MarketShareBlkInr
|
|
} else {
|
|
key = setting.MarketShareInr
|
|
}
|
|
|
|
listSpots, err := LoadLRangeList(key)
|
|
if err != nil {
|
|
applogger.Error("%v InitSubscribeShareInr.LoadLRangeList:%v", common.ErrShareInr, err)
|
|
return
|
|
}
|
|
|
|
for _, value := range listSpots {
|
|
SubscribeInrClosePrice(value) // 处理闭盘数据
|
|
}
|
|
|
|
time.Sleep(20 * time.Second)
|
|
}
|
|
}
|
|
|
|
// InitShareInrCloseNewPrice
|
|
//
|
|
// @Description: 同步实时行情
|
|
// @param check
|
|
func InitShareInrCloseNewPrice(check bool) {
|
|
for {
|
|
var key string
|
|
if check {
|
|
key = setting.MarketShareBlkInr
|
|
} else {
|
|
key = setting.MarketShareInr
|
|
}
|
|
listSpots, err := LoadLRangeList(key)
|
|
if err != nil {
|
|
applogger.Error("%v InitShareInrCloseNewPrice.LoadLRangeList:%v", common.ErrShareInr, err)
|
|
time.Sleep(20 * time.Second)
|
|
continue
|
|
}
|
|
|
|
for _, value := range listSpots {
|
|
SubscribeInrCloseNewPrice(value)
|
|
}
|
|
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
// InitShareInrPriceSetUp
|
|
//
|
|
// @Description: 同步插针行情
|
|
// @param check
|
|
func InitShareInrPriceSetUp(check bool) {
|
|
for {
|
|
var key string
|
|
if check {
|
|
key = setting.MarketShareBlkInr
|
|
} else {
|
|
key = setting.MarketShareInr
|
|
}
|
|
listSpots, err := LoadLRangeList(key)
|
|
if err != nil {
|
|
applogger.Error("%v InitShareInrPriceSetUp.LoadLRangeList:%v", common.ErrShareInr, err)
|
|
time.Sleep(20 * time.Second)
|
|
continue
|
|
}
|
|
|
|
for _, value := range listSpots {
|
|
inrKey := publicData.SymbolCache(flags.Inr, value, flags.TradeTypePrice)
|
|
inrSetCache := fmt.Sprintf("%v%v:%v", flags.StockTradePrices, flags.ShareInrMarketType, value)
|
|
vw, err := GetBeforeAndAfterSetPrice(inrSetCache)
|
|
if err != nil || len(vw) == 0 {
|
|
_ = memory.ShareInrPriceSetUp.Delete(inrKey)
|
|
continue
|
|
}
|
|
if err = memory.ShareInrPriceSetUp.Set(inrKey, []byte(vw)); err != nil {
|
|
applogger.Error("%v InitShareInrPriceSetUp.ShareInrPriceSetUp:%v", common.ErrShareInr, err)
|
|
}
|
|
}
|
|
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
// SubscribeInrHSetCodeList
|
|
//
|
|
// @Description: 同步列表缓存
|
|
// @param symbolStr
|
|
// @param check
|
|
func SubscribeInrHSetCodeList(symbolStr string, check bool) {
|
|
var key string
|
|
if check {
|
|
key = setting.MarketShareBlkInr
|
|
} else {
|
|
key = setting.MarketShareInr
|
|
}
|
|
// Write to the redis list hot cache for initializing subscriptions when the program is pulled up
|
|
checkBool, err := Reds.HExists(context.Background(), key, symbolStr).Result()
|
|
if err != nil {
|
|
return
|
|
}
|
|
if !checkBool {
|
|
if err := Reds.HSet(context.Background(), key, symbolStr, symbolStr).Err(); err != nil {
|
|
applogger.Error("%v SubscribeInrHSetCodeList.%v.HSet:%v", common.ErrShareInr, key, err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// SubscribeInrCloseNewPrice
|
|
//
|
|
// @Description: 获取行情价
|
|
// @param symbolStr
|
|
// @param check
|
|
func SubscribeInrCloseNewPrice(symbolStr string) {
|
|
// 获取市场真实开闭盘时间
|
|
timeValue, checkWeekday := MarketCheckOpenAndCloseTime(flags.ShareInrMarketType)
|
|
// 判定是否盘中
|
|
if utils.CheckInPlateTime(timeValue) && checkWeekday {
|
|
// 盘中实时价格
|
|
realTimePrice, err := Reds.HGet(context.Background(), flags.ShareIndiaClosingNewPriceKey, symbolStr).Result()
|
|
if err != nil {
|
|
realTimePrice = decimal.Zero.String()
|
|
}
|
|
if realTimePrice != decimal.Zero.String() {
|
|
keys := publicData.SymbolCache(flags.Inr, symbolStr, flags.TradeTypePrice)
|
|
if err = memory.ShareInrCache.Set(keys, []byte(realTimePrice)); err != nil {
|
|
applogger.Error("%v SubscribeInrCloseNewPrice.ShareInrCache:%v", common.ErrShareInr, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// SubscribeInrClosePrice
|
|
//
|
|
// @Description: 获取闭盘价
|
|
// @param symbolStr
|
|
func SubscribeInrClosePrice(symbolStr string) {
|
|
var err error
|
|
var sub = decimal.Zero
|
|
var closeNewPrice, closingPrice, price string
|
|
closeNewPrice, err = Reds.HGet(context.Background(), flags.ShareIndiaClosingNewPriceKey, symbolStr).Result()
|
|
if err != nil || closeNewPrice == decimal.Zero.String() {
|
|
closeNewPrice, err = Reds.HGet(context.Background(), flags.ShareIndiaClosingPriceKey, symbolStr).Result()
|
|
if err != nil || closeNewPrice == decimal.Zero.String() {
|
|
closeNewPrice = decimal.Zero.String()
|
|
}
|
|
}
|
|
|
|
// 写入闭盘价格
|
|
closingPrice, err = Reds.HGet(context.Background(), flags.ShareIndiaBeforeClose, symbolStr).Result()
|
|
if err != nil {
|
|
closingPrice = decimal.Zero.String()
|
|
}
|
|
|
|
// 判定取值数据
|
|
if closeNewPrice != decimal.Zero.String() {
|
|
price = closeNewPrice
|
|
} else {
|
|
price = closingPrice
|
|
}
|
|
closeKey := publicData.SymbolCache(flags.Inr, symbolStr, flags.TradeTypeClosePrice)
|
|
if err = memory.ShareInrClosePrice.Set(closeKey, []byte(price)); err != nil {
|
|
applogger.Error("%v SubscribeInrClosePrice.Set.price:%v", common.ErrShareInr, err)
|
|
}
|
|
|
|
// 写入涨跌幅价格判定缓存
|
|
cn := closeNewPrice != decimal.Zero.String()
|
|
cp := closingPrice != decimal.Zero.String()
|
|
lcn := utils.IsNumber(closeNewPrice)
|
|
lcp := utils.IsNumber(closingPrice)
|
|
if cn && cp && lcn && lcp {
|
|
sub = decimal.RequireFromString(closingPrice).Sub(decimal.RequireFromString(closeNewPrice))
|
|
}
|
|
chgKey := publicData.SymbolCache(flags.Inr, symbolStr, flags.TradeTypeChg) // 涨跌幅标识Key
|
|
if err = memory.ShareInrChgMark.Set(chgKey, []byte(sub.String())); err != nil {
|
|
applogger.Error("%v SubscribeInrClosePrice.Set.price:%v", common.ErrShareInr, err)
|
|
}
|
|
}
|
|
|
|
// OrderSubAdminShareInrSubscribeBySum
|
|
//
|
|
// @Description: 持仓订单浮动盈亏计算
|
|
// @param ctx
|
|
// @param uo
|
|
func OrderSubAdminShareInrSubscribeBySum(uo *Data) {
|
|
for {
|
|
var topIc = setting.AdminShareInrSubscribe
|
|
hashMap, err := uo.redisDB.HGetAll(context.Background(), topIc).Result()
|
|
if err != nil {
|
|
applogger.Error("OrderSubAdminShareInrSubscribeBySum.HGetAll:%v", err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
var hashList []share.ShareInrTallyCache
|
|
for _, value := range hashMap {
|
|
var msg share.ShareInrTallyCache
|
|
if err = json.Unmarshal([]byte(value), &msg); err != nil {
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
switch msg.Status {
|
|
case flags.Entrust: // 挂单
|
|
case flags.Position: // 持仓
|
|
hashList = append(hashList, msg)
|
|
default: // 平仓|撤单
|
|
err = uo.redisDB.HDel(context.Background(), topIc, msg.OrderId).Err()
|
|
if err != nil {
|
|
applogger.Error("OrderSubAdminShareInrSubscribeBySum.HDel:%v", err)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
applogger.Info("印度股数据量统计:%v", len(hashList))
|
|
// 统计印度股总持仓订单浮动盈亏
|
|
priceSum := decimal.Zero
|
|
for _, value := range hashList {
|
|
orderModel := shareData.ShareInrOrderProcessing(topIc, value)
|
|
if orderModel != nil {
|
|
var subPrice decimal.Decimal
|
|
newPrice, err := decimal.NewFromString(orderModel.Price)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
openPrice, err := decimal.NewFromString(orderModel.OpenPrice)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
switch orderModel.TradeType {
|
|
case flags.TradeTypeBuy: // 买涨 = 新价格 - 开仓价
|
|
subPrice = newPrice.Sub(openPrice)
|
|
case flags.TradeTypeSell: // 卖跌 = 开仓价 - 新价格
|
|
subPrice = openPrice.Sub(newPrice)
|
|
default:
|
|
subPrice = decimal.Zero
|
|
}
|
|
price := subPrice.Mul(decimal.RequireFromString(value.Order.OrderNumber))
|
|
priceSum = priceSum.Add(price) // 累加盈亏统计
|
|
}
|
|
}
|
|
// 写入缓存
|
|
if err = memory.ShareInrFloating.Set(flags.FloatingInr, []byte(priceSum.String())); err != nil {
|
|
applogger.Error("统计印度股持仓订单浮动盈亏错误:%v", err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
applogger.Info("统计印度股持仓订单浮动盈亏:%v", priceSum)
|
|
|
|
time.Sleep(1 * time.Second)
|
|
}
|
|
}
|
|
|
|
// SubscribeShareInr
|
|
// @Description: TODO: 印度股订阅
|
|
// @param ctx
|
|
// @param uo
|
|
// @param shareIdn
|
|
func SubscribeShareInr(ctx context.Context, shareInr *ShareInrSymbol, check bool) {
|
|
for {
|
|
select {
|
|
case symbol, _ := <-shareInr.InrMap:
|
|
symbolStr := string(symbol)
|
|
topIc := fmt.Sprintf("%v.%v", symbolStr, flags.CountryInr)
|
|
// Handling duplicate subscriptions
|
|
_, ok := shareInr.InrMapSymbol.Load(symbolStr)
|
|
if ok {
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
// Transaction determination
|
|
var key string
|
|
if check {
|
|
key = setting.MarketShareBlkInr // 大宗股交易
|
|
} else {
|
|
key = setting.MarketShareInr // 印度股交易
|
|
}
|
|
// Write to the redis list hot cache for initializing subscriptions when the program is pulled up
|
|
checkBool, err := Reds.HExists(context.Background(), key, symbolStr).Result()
|
|
if err != nil {
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
if !checkBool {
|
|
if err := Reds.HSet(context.Background(), key, symbolStr, symbolStr).Err(); err != nil {
|
|
applogger.Error("%v SubscribeShareInr.%v.HSet:%v", common.ErrShareInr, key, err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
}
|
|
|
|
// 处理订阅实时行情数据
|
|
go func() {
|
|
symbolStrCache := symbolStr
|
|
pubSub := Reds.Subscribe(ctx, topIc)
|
|
defer pubSub.Close()
|
|
if _, err := pubSub.Receive(ctx); err != nil {
|
|
shareInr.InrMapSymbol.Delete(symbolStrCache)
|
|
return
|
|
}
|
|
ch := pubSub.Channel()
|
|
for {
|
|
select {
|
|
case msg, _ := <-ch:
|
|
var subMsg ShareInrMessage
|
|
if err := json.Unmarshal([]byte(msg.Payload), &subMsg); err != nil {
|
|
applogger.Error("%v SubscribeShareInr.Unmarshal:%v", common.ErrShareInr, err)
|
|
time.Sleep(5 * time.Second)
|
|
return
|
|
}
|
|
SubscribeInrPrice(subMsg.Price.String(), symbolStr, flags.RealTime)
|
|
default:
|
|
Reds.Ping(ctx) // 如果没有消息,发送 PING 命令以维护连接
|
|
time.Sleep(10 * time.Second)
|
|
}
|
|
}
|
|
}()
|
|
|
|
// 盘前|盘后价格设置
|
|
_, okc := shareInr.InrSetMapSymbol.Load(symbolStr)
|
|
if !okc {
|
|
go func() {
|
|
for {
|
|
keyCache := fmt.Sprintf("%v%v:%v", flags.StockTradePrices, flags.ShareInrMarketType, symbolStr)
|
|
vw, err := GetBeforeAndAfterSetPrice(keyCache)
|
|
if err != nil || len(vw) == 0 {
|
|
priceCache := publicData.SymbolCache(flags.Inr, symbolStr, flags.TradeTypePrice)
|
|
memory.ShareInrPriceSetUp.Delete(priceCache)
|
|
time.Sleep(15 * time.Second)
|
|
continue
|
|
}
|
|
SubscribeInrPrice(vw, symbolStr, flags.SetUp)
|
|
time.Sleep(10 * time.Second)
|
|
}
|
|
}()
|
|
// Write cache to determine whether to repeatedly open the protocol
|
|
shareInr.InrSetMapSymbol.Store(symbolStr, symbolStr)
|
|
}
|
|
|
|
// Write in the map to determine whether to repeat subscription
|
|
shareInr.InrMapSymbol.Store(symbolStr, symbolStr)
|
|
}
|
|
}
|
|
}
|
|
|
|
// SubscribeInrPrice
|
|
//
|
|
// @Description: TODO: 订阅获取印度股实时价格或者[盘前|盘后]设置价格
|
|
// @param setPrice
|
|
// @param symbolStr
|
|
// @param check
|
|
func SubscribeInrPrice(setPrice, symbolStr string, check int) {
|
|
var err error
|
|
var sub = decimal.Zero
|
|
|
|
// 计算涨跌幅
|
|
yClosingPrice, err := Reds.HGet(context.Background(), flags.ShareIndiaClosingPriceKey, symbolStr).Result()
|
|
if err != nil || yClosingPrice == decimal.Zero.String() {
|
|
yClosingPrice, err = Reds.HGet(context.Background(), flags.ShareIndiaClosingNewPriceKey, symbolStr).Result()
|
|
if err != nil || yClosingPrice == decimal.Zero.String() {
|
|
yClosingPrice = setPrice
|
|
}
|
|
}
|
|
|
|
// 写入涨跌幅缓存数据
|
|
yc := yClosingPrice != decimal.Zero.String()
|
|
sp := setPrice != decimal.Zero.String()
|
|
lyc := utils.IsNumber(yClosingPrice)
|
|
lsp := utils.IsNumber(setPrice)
|
|
if yc && sp && lyc && lsp {
|
|
sub = decimal.RequireFromString(setPrice).Sub(decimal.RequireFromString(yClosingPrice))
|
|
}
|
|
chgKey := publicData.SymbolCache(flags.Inr, symbolStr, flags.TradeTypeChg) // 涨跌幅标识Key
|
|
if err = memory.ShareInrChgMark.Set(chgKey, []byte(sub.String())); err != nil {
|
|
applogger.Error("%v SubscribeInrPrice.ShareIdnChgMark.Set.price:%v", common.ErrShareInr, err)
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("涨跌幅交易对内存key:%v,涨跌幅数值:%v", symbolStr, sub)
|
|
}
|
|
|
|
// 交易类型:0最新价,1买入,2卖出
|
|
price := publicData.SymbolCache(flags.Inr, symbolStr, flags.TradeTypePrice)
|
|
switch check {
|
|
case flags.RealTime: // 实时价格(优先级高)
|
|
if err = memory.ShareInrCache.Set(price, []byte(setPrice)); err != nil {
|
|
applogger.Error("%v SubscribeInrPrice.ShareInrCache.Set.price:%v", common.ErrShareInr, err)
|
|
}
|
|
case flags.SetUp: // 设置[盘前|盘后]价格
|
|
if err = memory.ShareInrPriceSetUp.Set(price, []byte(setPrice)); err != nil {
|
|
applogger.Error("%v SubscribeInrPrice.ShareInrPriceSetUp:%v", common.ErrShareInr, err)
|
|
}
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("股票交易对内存Key:%v,最新价格:%v", price, setPrice)
|
|
}
|
|
}
|
|
|
|
// SubscribeInrSetForcedClosure
|
|
//
|
|
// @Description: TODO: 处理印度股强平阈值
|
|
// @param symbolStr
|
|
func SubscribeInrSetForcedClosure(symbolStr string) {
|
|
flatRatio := GetCacheForcedClosure(flags.StockYDSystemSetUpKey, symbolStr)
|
|
chgKey := publicData.SymbolCache(flags.Inr, symbolStr, flags.TradeTypeForcedClosure)
|
|
if err := memory.ShareInrForcedClosure.Set(chgKey, []byte(flatRatio.String())); err != nil {
|
|
applogger.Error("%v SubscribeInrSetForcedClosure.StockYDSystemSetUpKey err:%v", common.ErrShareInr, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
// ShareInrTransactionEntrust
|
|
//
|
|
// @Description: 印度股委托订单
|
|
// @param ctx
|
|
func ShareInrTransactionEntrust(ctx context.Context) {
|
|
for {
|
|
ShareInrTransactionCalculationEntrust(ctx)
|
|
time.Sleep(600 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
// ShareInrTransactionCalculationEntrust
|
|
//
|
|
// @Description: 印度股挂单缓存队列计算
|
|
// @param ctx
|
|
// @param uo
|
|
func ShareInrTransactionCalculationEntrust(ctx context.Context) {
|
|
var wg sync.WaitGroup
|
|
|
|
// 全局变量处理
|
|
if CheckGlobalTread(flags.InrMarket) {
|
|
time.Sleep(5 * time.Second)
|
|
return
|
|
}
|
|
|
|
// 获取印度股挂单缓存列表
|
|
orderMap, err := Reds.HGetAll(context.Background(), setting.MarketShareInrEntrust).Result()
|
|
if err != nil {
|
|
applogger.Error("%v ShareInrTransactionCalculationEntrust.HGetAll:%v", common.ErrShareInr, err)
|
|
return
|
|
}
|
|
|
|
for _, value := range orderMap {
|
|
var msg = make(chan share.ShareInrTallyCache, 1)
|
|
var entrust share.ShareInrTallyCache
|
|
if err = json.Unmarshal([]byte(value), &entrust); err != nil {
|
|
applogger.Error("%v ShareInrTransactionCalculationEntrust.Unmarshal:%v", common.ErrShareInr, err)
|
|
continue
|
|
}
|
|
|
|
// 股票实时价格
|
|
var newPrice decimal.Decimal
|
|
newPrice, err = GetShareInrPrice(entrust.Symbol)
|
|
if err != nil {
|
|
applogger.Warn("%v ShareInrTransactionCalculationEntrust.Get:%v---%v", common.ErrShareInr, entrust.Symbol, err)
|
|
continue
|
|
}
|
|
|
|
// 判定涨跌幅
|
|
chg := GetShareChgInr(flags.Inr, entrust.Symbol) // 涨跌幅标识
|
|
if share.CheckInrOrderByChg(setting.MarketShareInrEntrust, entrust, chg) {
|
|
//applogger.Warn("当前股票%v订单在挂单状态已达到涨跌幅上限.", entrust.Symbol)
|
|
continue
|
|
}
|
|
|
|
wg.Add(1)
|
|
go func(value string) {
|
|
var resultMsg share.ShareInrTallyCache
|
|
switch entrust.Order.DealType {
|
|
case flags.DealTypeLimited: // 限价挂单
|
|
resultMsg = ShareInrConcurrentComputingEntrustLimited(&entrust, newPrice, &wg)
|
|
case flags.DealTypeMarket: // 市价挂单(开盘即成交)
|
|
resultMsg = ShareInrConcurrentComputingEntrustMarket(&entrust, newPrice, &wg)
|
|
}
|
|
msg <- resultMsg // 通知管道异步处理订单操作
|
|
}(value)
|
|
|
|
// 处理并发结果(需要改成通过信道通知)
|
|
select {
|
|
case resultMsg, _ := <-msg:
|
|
switch resultMsg.Status {
|
|
case flags.Entrust: // 挂单中
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("从信道接收印度股挂单信息:%v", resultMsg)
|
|
}
|
|
case flags.Position: // 持仓中
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("从信道接收到印度股持仓信息:%v", resultMsg)
|
|
}
|
|
|
|
// 开盘逻辑
|
|
if err = ShareInrLiquidationEntrust(ctx, &resultMsg); err != nil {
|
|
applogger.Warn("%v ShareInrTransactionCalculationEntrust.ShareInrLiquidationEntrust:%v", common.ErrShareInr, err)
|
|
continue
|
|
}
|
|
|
|
// 写入持仓缓存列表
|
|
var byteStr []byte
|
|
byteStr, err = json.Marshal(resultMsg)
|
|
if err != nil {
|
|
applogger.Error("%v ShareInrTransactionCalculationEntrust.Marshal:%v", common.ErrShareInr, err)
|
|
continue
|
|
}
|
|
|
|
// TODO: 写入持仓消息队列
|
|
//if err = uo.mqProducer.Entrust.PushNotice(byteStr); err != nil {
|
|
// applogger.Error("%v ShareInrTransactionCalculationEntrust.EntrustPushNotice:%v", common.ShareInrError, err)
|
|
// continue
|
|
//}
|
|
|
|
// 写入持仓队列缓存
|
|
if err = Reds.HSet(context.Background(), setting.MarketShareInrPosition, resultMsg.OrderId, string(byteStr)).Err(); err != nil {
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wg.Wait()
|
|
applogger.Info("印度股挂单并发计算执行完毕......")
|
|
}
|
|
|
|
// ShareInrConcurrentComputingEntrustLimited
|
|
//
|
|
// @Description: 印度股挂单(限价|市价)缓存列表业务处理
|
|
// @param order
|
|
// @param newPrice
|
|
// @param bidPrice
|
|
// @param askPrice
|
|
// @param wg
|
|
// @return tradedeal.ShareInrTallyCache
|
|
func ShareInrConcurrentComputingEntrustLimited(order *share.ShareInrTallyCache, newPrice decimal.Decimal, wg *sync.WaitGroup) share.ShareInrTallyCache {
|
|
var deleteCache bool
|
|
var dealPrice string
|
|
var limitPrice = decimal.RequireFromString(order.Order.LimitPrice) // 限价-价格
|
|
var status = order.Status // 原始价格
|
|
|
|
switch order.Order.TradeType {
|
|
case flags.TradeTypeBuy: // 买涨
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("用户ID:%v,限价买入下单价格:%v,最新市价:%v,判定结果:%v,原始状态:%v", order.UserId, limitPrice, newPrice, limitPrice.Cmp(newPrice), order.Status)
|
|
}
|
|
|
|
// 限价买入逻辑判定 -> 挂单金额 > 当前价格
|
|
if limitPrice.Cmp(newPrice) > 0 {
|
|
deleteCache = true
|
|
difference := newPrice.Mul(utils.Difference()) // 设置价差
|
|
dealPrice = newPrice.Add(difference).String() // 开仓价格
|
|
}
|
|
case flags.TradeTypeSell: // 买跌
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("用户ID:%v,限价卖出下单价格:%v,最新市价:%v,判定结果:%v,原始状态:%v", order.UserId, limitPrice, newPrice, limitPrice.Cmp(newPrice), order.Status)
|
|
}
|
|
|
|
// 限价卖入逻辑判定 -> 挂单金额 < 当前价格
|
|
if limitPrice.Cmp(newPrice) < 0 {
|
|
deleteCache = true
|
|
difference := newPrice.Mul(utils.Difference()) // 设置价差
|
|
dealPrice = newPrice.Sub(difference).String() // 开仓价格
|
|
}
|
|
}
|
|
|
|
if deleteCache {
|
|
order.Status = flags.Position
|
|
if err := Reds.HDel(context.Background(), setting.MarketShareInrEntrust, order.OrderId).Err(); err != nil {
|
|
applogger.Error("%v ShareInrConcurrentComputingEntrustLimited.HDel:%v", common.ErrShareInr, err)
|
|
order.Status = status
|
|
}
|
|
}
|
|
|
|
wg.Done()
|
|
return share.ShareInrTallyCache{
|
|
UserId: order.UserId, // 用户Id
|
|
OrderId: order.OrderId, // 订单Id
|
|
Symbol: order.Symbol, // 下单交易对
|
|
OpenPrice: dealPrice, // 开仓价格
|
|
Status: order.Status, // 订单状态
|
|
Order: order.Order, // 下单信息
|
|
ClosingTime: order.ClosingTime, // 平仓时间
|
|
}
|
|
}
|
|
|
|
// ShareInrConcurrentComputingEntrustMarket
|
|
//
|
|
// @Description: 印度股市价下单进入挂单队列(休市)
|
|
// @param order
|
|
// @param newPrice
|
|
// @param bidPrice
|
|
// @param askPrice
|
|
// @param wg
|
|
// @return tradedeal.ShareInrTallyCache
|
|
func ShareInrConcurrentComputingEntrustMarket(order *share.ShareInrTallyCache, newPrice decimal.Decimal, wg *sync.WaitGroup) share.ShareInrTallyCache {
|
|
var deleteCache bool
|
|
var dealPrice string
|
|
var marketPrice = decimal.RequireFromString(order.Order.MarketPrice) // 市价-价格
|
|
var status = order.Status // 原始价格
|
|
|
|
switch order.Order.TradeType {
|
|
case flags.TradeTypeBuy: // 买涨
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("用户ID:%v,限价买入下单价格:%v,最新市价:%v,原始状态:%v", order.UserId, marketPrice, newPrice, order.Status)
|
|
}
|
|
|
|
deleteCache = true
|
|
difference := newPrice.Mul(utils.Difference()) // 设置价差
|
|
dealPrice = newPrice.Add(difference).String() // 开仓价格
|
|
case flags.TradeTypeSell: // 买跌
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("用户ID:%v,限价卖出下单价格:%v,最新市价:%v,原始状态:%v", order.UserId, marketPrice, newPrice, order.Status)
|
|
}
|
|
|
|
deleteCache = true
|
|
difference := newPrice.Mul(utils.Difference()) // 设置价差
|
|
dealPrice = newPrice.Sub(difference).String() // 开仓价格
|
|
}
|
|
|
|
if deleteCache {
|
|
order.Status = flags.Position
|
|
if err := Reds.HDel(context.Background(), setting.MarketShareInrEntrust, order.OrderId).Err(); err != nil {
|
|
applogger.Error("%v ShareInrConcurrentComputingEntrustMarket.HDel:%v", common.ErrShareInr, err)
|
|
order.Status = status
|
|
}
|
|
}
|
|
|
|
wg.Done()
|
|
return share.ShareInrTallyCache{
|
|
UserId: order.UserId, // 用户Id
|
|
OrderId: order.OrderId, // 订单Id
|
|
Symbol: order.Symbol, // 下单交易对
|
|
OpenPrice: dealPrice, // 开仓价格
|
|
Status: order.Status, // 订单状态
|
|
Order: order.Order, // 下单信息
|
|
ClosingTime: order.ClosingTime, // 平仓时间
|
|
}
|
|
}
|
|
|
|
// ShareBlockInrConcurrentComputingEntrustMarket
|
|
//
|
|
// @Description: 大宗(印尼股)交易
|
|
// @param order
|
|
// @param newPrice
|
|
// @param wg
|
|
// @return share.ShareInrTallyCache
|
|
func ShareBlockInrConcurrentComputingEntrustMarket(order *share.ShareInrTallyCache, newPrice decimal.Decimal, wg *sync.WaitGroup) share.ShareInrTallyCache {
|
|
var status = order.Status // 原始状态
|
|
|
|
order.Status = flags.Position
|
|
if err := Reds.HDel(context.Background(), setting.MarketShareBlkEntrust, order.OrderId).Err(); err != nil {
|
|
applogger.Error("%v ShareBlockInrConcurrentComputingEntrustMarket.HDel:%v", common.ErrShareBlk, err)
|
|
order.Status = status
|
|
}
|
|
|
|
wg.Done()
|
|
return share.ShareInrTallyCache{
|
|
UserId: order.UserId, // 用户Id
|
|
OrderId: order.OrderId, // 订单Id
|
|
Symbol: order.Symbol, // 下单交易对
|
|
OpenPrice: newPrice.String(), // 开仓价格
|
|
Status: order.Status, // 订单状态
|
|
Order: order.Order, // 下单信息
|
|
ClosingTime: order.ClosingTime, // 平仓时间
|
|
}
|
|
}
|
|
|
|
// ShareInrMqOpenBusiness
|
|
//
|
|
// @Description: TODO: 印度股持仓消息队列
|
|
// @param ctx
|
|
// @param uo
|
|
func ShareInrMqOpenBusiness(ctx context.Context, uo *Data) {
|
|
go func() {
|
|
uo.mqConsumer.Entrust.ConsumerNotice()
|
|
}()
|
|
for {
|
|
select {
|
|
case message, ok := <-consumer.ConsumerEntrustMq.ShareInrMq:
|
|
if !ok {
|
|
time.Sleep(5 * time.Second)
|
|
applogger.Error("%v ShareInrMqOpenBusiness.ShareInrMq err....", common.ErrShareInr)
|
|
continue
|
|
}
|
|
|
|
// 持仓订单缓存数据序列化解析
|
|
var resultMsg share.ShareInrTallyCache
|
|
if err := json.Unmarshal(message, &resultMsg); err != nil {
|
|
applogger.Error("%v ShareInrMqOpenBusiness.Unmarshal:%v", common.ErrShareInr, err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
|
|
// 持仓平仓
|
|
if err := ShareInrLiquidationEntrust(ctx, &resultMsg); err != nil {
|
|
applogger.Error("%v ShareInrMqOpenBusiness.ShareInrLiquidationEntrust:%v", common.ErrShareInr, err)
|
|
continue
|
|
}
|
|
default:
|
|
// TODO: 是否处理空队列缓存的情况
|
|
applogger.Error("这里没有监控到持仓mq队列消息.........")
|
|
time.Sleep(2 * time.Second)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ShareInrLiquidationEntrust
|
|
//
|
|
// @Description: 印度股挂单-->开仓业务处理
|
|
// @param ctx
|
|
// @param order
|
|
// @return error
|
|
func ShareInrLiquidationEntrust(ctx context.Context, order *share.ShareInrTallyCache) error {
|
|
// 1、开盘
|
|
err := StockInrOpenOrder(ctx, Msql, order.UserId, order.OrderId, order.OpenPrice, order.Order)
|
|
if err != nil {
|
|
applogger.Error("%v ShareInrLiquidationEntrust.StockInrOpenOrder:%v", common.ErrShareInr, err)
|
|
return err
|
|
}
|
|
|
|
// 大宗(印度股)交易判定
|
|
var entrustKey, adminKey string
|
|
if !CheckTypeStatus(order.Order.Type) {
|
|
entrustKey = setting.ShareInrSubscribe
|
|
adminKey = setting.AdminShareInrSubscribe
|
|
} else {
|
|
entrustKey = setting.ShareBlkSubscribe
|
|
adminKey = setting.AdminShareBlkSubscribe
|
|
}
|
|
|
|
// 2、更新用户订阅缓存列表订单状态
|
|
updateKey := virtual.OrderIdListKey(entrustKey, order.UserId)
|
|
if err = UpdateShareInrSubscribeHashStatusByOrderId(order.OrderId, updateKey, flags.Position, order.OpenPrice); err != nil {
|
|
applogger.Error("%v ShareInrLiquidationEntrust.Entrust.%v:%v", common.ErrShareInr, entrustKey, err)
|
|
return err
|
|
}
|
|
|
|
// 3、更新管理员订阅缓存列表订单状态
|
|
if err = UpdateShareInrSubscribeHashStatusByOrderId(order.OrderId, adminKey, flags.Position, order.OpenPrice); err != nil {
|
|
applogger.Error("%v ShareInrLiquidationEntrust.Entrust.%v:%v", common.ErrShareInr, adminKey, err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ShareInrTransactionPosition
|
|
//
|
|
// @Description: 印度股持仓订单
|
|
// @param ctx
|
|
func ShareInrTransactionPosition(ctx context.Context) {
|
|
for {
|
|
ShareInrTransactionCalculationPosition(ctx)
|
|
time.Sleep(600 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
// ShareInrTransactionCalculationPosition
|
|
//
|
|
// @Description: 印尼股持仓缓存队列计算
|
|
// @param ctx
|
|
func ShareInrTransactionCalculationPosition(ctx context.Context) {
|
|
var wg sync.WaitGroup
|
|
|
|
// 判定是否交易
|
|
if CheckGlobalTread(flags.InrMarket) {
|
|
time.Sleep(5 * time.Second)
|
|
return
|
|
}
|
|
|
|
// TODO: 获取IPO未支付订单缓存
|
|
userIdMap, _ := GetBotUserArrears(ctx)
|
|
|
|
// 获取持仓缓存列表
|
|
orderMap, err := Reds.HGetAll(context.Background(), setting.MarketShareInrPosition).Result()
|
|
if err != nil {
|
|
applogger.Error("%v ShareInrTransactionCalculationPosition.HGetAll:%v", common.ErrShareInr, err)
|
|
return
|
|
}
|
|
|
|
for _, value := range orderMap {
|
|
var msg = make(chan share.ShareInrTallyCache, 1)
|
|
var entrust share.ShareInrTallyCache
|
|
if err = json.Unmarshal([]byte(value), &entrust); err != nil {
|
|
applogger.Error("%v ShareInrTransactionCalculationPosition.Unmarshal:%v", common.ErrShareInr, err)
|
|
continue
|
|
}
|
|
|
|
// TODO: 判定是否未IPO未支付订单-不能平仓
|
|
_, isOk := userIdMap[entrust.UserId]
|
|
if isOk {
|
|
continue
|
|
}
|
|
|
|
// 处理时间
|
|
if !CheckShareSystemTime(entrust.ClosingTime) {
|
|
applogger.Info("印度股:%v,平仓时间:%v暂未到达...", entrust.Symbol, entrust.ClosingTime)
|
|
continue
|
|
}
|
|
|
|
// TODO: 实时获取强平阈值
|
|
//entrust.Order.System.StrongFlatRatio = GetForcedClosureValue(flags.Inr, entrust.Symbol)
|
|
|
|
// 实时价格
|
|
var newPrice decimal.Decimal
|
|
newPrice, err = GetShareInrPrice(entrust.Symbol)
|
|
if err != nil {
|
|
applogger.Warn("%v ShareInrTransactionCalculationPosition.Get:%v--%v", common.ErrShareInr, entrust.Symbol, err)
|
|
continue
|
|
}
|
|
|
|
// 判定涨跌幅
|
|
chg := GetShareChgInr(flags.Inr, entrust.Symbol) // 涨跌幅标识
|
|
if share.CheckInrOrderByChg(setting.MarketShareInrEntrust, entrust, chg) {
|
|
//applogger.Warn("当前股票%v订单在挂单状态已达到涨跌幅上限.", entrust.Symbol)
|
|
continue
|
|
}
|
|
|
|
// 判定配额强平
|
|
checkFlattening := GetStrongFlatteningThreshold(entrust.UserId)
|
|
|
|
wg.Add(1)
|
|
go func(value string) {
|
|
resultMsg := ShareInrConcurrentComputingPosition(&entrust, newPrice, &wg, checkFlattening)
|
|
msg <- resultMsg
|
|
}(value)
|
|
|
|
// 处理并发结果
|
|
select {
|
|
case resultMsg, _ := <-msg:
|
|
switch resultMsg.Status {
|
|
case flags.Position: // 持仓
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("从信道接收到印度股持仓信息:%v", resultMsg)
|
|
}
|
|
case flags.Close: // 平仓
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("从信道接收到印度股平仓信息:%v", resultMsg)
|
|
}
|
|
|
|
// TODO: 平仓操作(优化写入队列中等待平仓)
|
|
//var byteStr []byte
|
|
//byteStr, err = json.Marshal(resultMsg)
|
|
//if err != nil {
|
|
// applogger.Error("%v ShareInrTransactionCalculationPosition.Marshal:%v", common.ShareInrError, err)
|
|
// continue
|
|
//}
|
|
//if err = uo.mqProducer.Position.PushNotice(byteStr); err != nil {
|
|
// applogger.Error("%v ShareInrTransactionCalculationPosition.DealPublish:%v", common.ShareInrError, err)
|
|
// continue
|
|
//}
|
|
|
|
if err = ShareInrLiquidationPosition(ctx, &resultMsg); err != nil {
|
|
applogger.Error("%v ShareInrTransactionCalculationPosition.ShareInrLiquidationPosition:%v", common.ErrShareInr, err)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wg.Wait()
|
|
applogger.Info("印度股持仓并发计算执行完毕......")
|
|
}
|
|
|
|
// ShareInrConcurrentComputingPosition
|
|
//
|
|
// @Description: 印度股持仓缓存列表业务处理
|
|
// @param order
|
|
// @param newPrice
|
|
// @param bidPrice
|
|
// @param askPrice
|
|
// @param wg
|
|
// @return tradedeal.ShareInrTallyCache
|
|
func ShareInrConcurrentComputingPosition(order *share.ShareInrTallyCache, newPrice decimal.Decimal, wg *sync.WaitGroup, checkFlattening bool) share.ShareInrTallyCache {
|
|
var deleteCache, checkBool bool
|
|
var dealPrice string
|
|
var sellShort decimal.Decimal
|
|
var openPrice = decimal.RequireFromString(order.OpenPrice) // 限价
|
|
var orderNumber = decimal.RequireFromString(order.Order.OrderNumber) // 仓位
|
|
|
|
var pryNum decimal.Decimal
|
|
lenPryNum := len(utils.ReplaceStr(order.Order.PryNum)) == 0
|
|
if lenPryNum || order.Order.PryNum == flags.SetZero || order.Order.System.UserStatus != flags.SetThree || !utils.IsNumberInt(order.Order.PryNum) {
|
|
pryNum = decimal.RequireFromString(flags.SetOne)
|
|
} else {
|
|
pryNum = decimal.RequireFromString(order.Order.PryNum)
|
|
}
|
|
|
|
// 下单判定设置(false无设置|true止盈止损)
|
|
_, stopWinPrice, stopLossPrice, _ := StockInrVoteStopType(order.Order)
|
|
|
|
switch order.Order.TradeType {
|
|
case flags.TradeTypeBuy: // 买涨(强平)
|
|
if !flags.CheckSetting {
|
|
applogger.Info("用户ID:%v,持仓开仓价格:%v,最新市价:%v,止盈:%v,止损:%v,原始状态:%v", order.UserId, openPrice, newPrice, stopWinPrice, stopLossPrice, order.Status)
|
|
}
|
|
// 买涨:挂止损止盈,止盈价必须<当前价,止损价必须>当前价;
|
|
if !stopWinPrice.IsZero() {
|
|
if stopWinPrice.Cmp(newPrice) < 0 {
|
|
checkBool = true
|
|
difference := newPrice.Mul(utils.Difference()) // 设置价差
|
|
dealPrice = newPrice.Sub(difference).String() // 平仓价格
|
|
}
|
|
}
|
|
if !stopLossPrice.IsZero() {
|
|
if stopLossPrice.Cmp(newPrice) > 0 {
|
|
checkBool = true
|
|
difference := newPrice.Mul(utils.Difference()) // 设置价差
|
|
dealPrice = newPrice.Add(difference).String() // 平仓价格
|
|
}
|
|
}
|
|
// 强行平仓(做多)
|
|
if !checkBool {
|
|
sellShort = newPrice.Sub(openPrice).Mul(orderNumber)
|
|
}
|
|
case flags.TradeTypeSell: // 买跌(存在强行平仓)
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("用户ID:%v,限价持仓买跌下单价格:%v,最新市价:%v,止盈:%v,止损:%v,原始状态:%v", order.UserId, openPrice, newPrice, stopWinPrice, stopLossPrice, order.Status)
|
|
}
|
|
// 买跌:挂止损止盈,止盈价必须>当前价,止损价必须<当前价;
|
|
if !stopWinPrice.IsZero() {
|
|
if stopWinPrice.Cmp(newPrice) > 0 {
|
|
checkBool = true
|
|
difference := newPrice.Mul(utils.Difference()) // 设置价差
|
|
dealPrice = newPrice.Add(difference).String() // 平仓价格
|
|
}
|
|
}
|
|
if !stopLossPrice.IsZero() {
|
|
if stopLossPrice.Cmp(newPrice) < 0 {
|
|
checkBool = true
|
|
difference := newPrice.Mul(utils.Difference()) // 设置价差
|
|
dealPrice = newPrice.Sub(difference).String() // 平仓价格
|
|
}
|
|
}
|
|
// 强行平仓(做空)
|
|
if !checkBool {
|
|
sellShort = openPrice.Sub(newPrice).Mul(orderNumber)
|
|
}
|
|
}
|
|
/* 强行平仓(做多|做空)
|
|
1、做多:(最新成交价-开仓成交价)*仓位
|
|
2、做空:(开仓成交价-最新成交价)*仓位
|
|
3、当浮动盈亏 >= 保证金的70%订单强行平仓
|
|
*/
|
|
if sellShort.IsNegative() && checkFlattening {
|
|
orderAmount := newPrice.Mul(decimal.RequireFromString(order.Order.OrderNumber)).Div(pryNum) // 订单金额 = 当前价格 * 订单数量 / 杠杆
|
|
floatPrice := orderAmount.Mul(decimal.RequireFromString(order.Order.System.StrongFlatRatio))
|
|
if !flags.CheckSetting {
|
|
applogger.Debug("强平保证金:%v,强平浮动70:%v,强行平仓判定:%v", orderAmount, floatPrice, sellShort.Abs().Cmp(floatPrice))
|
|
}
|
|
|
|
if sellShort.Abs().Cmp(floatPrice) >= 0 {
|
|
checkBool = true
|
|
// 设置价差
|
|
difference := newPrice.Mul(utils.Difference()) // 设置价差
|
|
switch order.Order.TradeType {
|
|
case flags.TradeTypeBuy: //买涨
|
|
dealPrice = newPrice.Sub(difference).String() // 平仓价格
|
|
case flags.TradeTypeSell: // 买跌
|
|
dealPrice = newPrice.Add(difference).String() // 平仓价格
|
|
}
|
|
}
|
|
}
|
|
// 交易状态判定
|
|
if checkBool {
|
|
deleteCache = true
|
|
order.Status = flags.Close
|
|
}
|
|
if deleteCache {
|
|
// 根据订单ID-删除持仓列表缓存订单
|
|
if err := Reds.HDel(context.Background(), setting.MarketShareInrPosition, order.OrderId).Err(); err != nil {
|
|
applogger.Error("%v ShareInrConcurrentComputingPosition.Position.HDel:%v", common.ErrShareInr, err)
|
|
}
|
|
}
|
|
|
|
wg.Done()
|
|
return share.ShareInrTallyCache{
|
|
UserId: order.UserId, // 用户Id
|
|
OrderId: order.OrderId, // 订单Id
|
|
Symbol: order.Symbol, // 下单交易对
|
|
ClosingPrice: dealPrice, // 平仓价格
|
|
Status: order.Status, // 订单状态
|
|
Order: order.Order, // 下单信息
|
|
ClosingTime: order.ClosingTime, // 平仓时间
|
|
}
|
|
}
|
|
|
|
// ShareInrMqClosingBusiness
|
|
//
|
|
// @Description: TODO: 处理印度股平仓消息队列
|
|
// @param ctx
|
|
// @param uo
|
|
func ShareInrMqClosingBusiness(ctx context.Context, uo *Data) {
|
|
go func() {
|
|
uo.mqConsumer.Position.ConsumerNotice()
|
|
}()
|
|
for {
|
|
select {
|
|
case message, ok := <-consumer.ConsumerPositionMq.ShareInrMq:
|
|
if !ok {
|
|
time.Sleep(5 * time.Second)
|
|
applogger.Error("%v ShareInrMqClosingBusiness.ShareInrMq err....", common.ErrShareInr)
|
|
continue
|
|
}
|
|
applogger.Info("接收到平仓信息:%v", string(message))
|
|
|
|
// 持仓订单缓存数据序列化解析
|
|
var resultMsg share.ShareInrTallyCache
|
|
if err := json.Unmarshal(message, &resultMsg); err != nil {
|
|
applogger.Error("%v ShareInrMqClosingBusiness.Unmarshal:%v", common.ErrShareInr, err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
|
|
// 持仓平仓
|
|
if err := ShareInrLiquidationPosition(ctx, &resultMsg); err != nil {
|
|
applogger.Error("%v ShareInrMqClosingBusiness.ShareInrLiquidationPosition:%v", common.ErrShareInr, err)
|
|
continue
|
|
}
|
|
default:
|
|
// TODO: 是否处理空队列缓存的情况
|
|
time.Sleep(2 * time.Second)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ShareInrLiquidationPosition
|
|
//
|
|
// @Description: 印度股持仓-->平仓业务处理
|
|
// @param ctx
|
|
// @param order
|
|
// @return error
|
|
func ShareInrLiquidationPosition(ctx context.Context, order *share.ShareInrTallyCache) error {
|
|
// 1、平仓操作
|
|
err := StockInrClosingOrder(ctx, Msql, order.OrderId, order.ClosingPrice, order.Order)
|
|
if err != nil {
|
|
applogger.Error("%v ShareInrLiquidationPosition.StockIdnClosingOrder:%v", common.ErrShareInr, err)
|
|
return err
|
|
}
|
|
|
|
// 2、平仓更新用户订阅订单状态
|
|
userSubKey := virtual.OrderIdListKey(setting.ShareInrSubscribe, order.UserId)
|
|
if err = UpdateShareInrSubscribeHashStatusByOrderId(order.OrderId, userSubKey, flags.Close, flags.SetNull); err != nil {
|
|
applogger.Error("%v ShareInrLiquidationPosition.Position.ShareInrSubscribe:%v", common.ErrShareInr, err)
|
|
return err
|
|
}
|
|
|
|
// 3、平仓更新管理员订阅订单状态
|
|
if err = UpdateShareInrSubscribeHashStatusByOrderId(order.OrderId, setting.AdminShareInrSubscribe, flags.Close, flags.SetNull); err != nil {
|
|
applogger.Error("%v ShareInrLiquidationPosition.Position.AdminShareInrSubscribe:%v", common.ErrShareInr, err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// StockInrVoteStopType
|
|
//
|
|
// @Description: 印度股判定取值止损止盈
|
|
// @param order
|
|
// @return bool
|
|
// @return decimal.Decimal
|
|
// @return decimal.Decimal
|
|
// @return error
|
|
func StockInrVoteStopType(order structure.ShareOrder) (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: // 设置止盈止损
|
|
checkBool = true
|
|
stopWinPrice, _ = decimal.NewFromString(order.StopWinPrice)
|
|
stopLossPrice, _ = decimal.NewFromString(order.StopLossPrice)
|
|
default:
|
|
return checkBool, stopWinPrice, stopLossPrice, flags.ErrContractThirteen
|
|
}
|
|
|
|
return checkBool, stopWinPrice, stopLossPrice, nil
|
|
}
|
|
|
|
// GetShareInrPrice
|
|
//
|
|
// @Description: 查询印度股股票价格
|
|
// @param symbol
|
|
// @return decimal.Decimal
|
|
// @return decimal.Decimal
|
|
// @return decimal.Decimal
|
|
// @return error
|
|
func GetShareInrPrice(symbol string) (decimal.Decimal, error) {
|
|
var err error
|
|
var priceByte []byte
|
|
var newPrice decimal.Decimal
|
|
|
|
key := publicData.SymbolCache(flags.Inr, symbol, flags.TradeTypePrice)
|
|
priceByte, err = memory.GetShareInrCache(key)
|
|
if err != nil {
|
|
return decimal.Decimal{}, err
|
|
}
|
|
|
|
newPrice, err = decimal.NewFromString(string(priceByte))
|
|
if err != nil {
|
|
return decimal.Decimal{}, err
|
|
}
|
|
|
|
applogger.Info("shareInrCode:%v,topIc:%v,shareInrPrice:%v", symbol, key, newPrice)
|
|
|
|
return newPrice, nil
|
|
}
|
|
|