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.
1123 lines
37 KiB
1123 lines
37 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/optionData"
|
|
"matchmaking-system/internal/data/socket/publicData"
|
|
"matchmaking-system/internal/data/tradedeal/option"
|
|
"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"
|
|
)
|
|
|
|
/**
|
|
期权-交易计算相关公式
|
|
一、手续费(Total Fee)
|
|
1> 固定费用:Total Fee = Total Fee Fix Value(固定费用)
|
|
2> 按比例结算:Total Fee = Total Fee Ratio(总费用比例) * Option Filled Price(开仓价格) * Quantity(订单数量)
|
|
3> 按张结算:Total Fee = Total Fee Per Contract(每份费用) * Quantity(订单数量)
|
|
三、浮动盈亏(P/L)
|
|
1>buy call & buy put
|
|
1> bid买一价为0, P/L显示为 -
|
|
2> bid买一价大于0, P/L =(bid买一价 - Cost Price)*Contracts Quantity
|
|
2>sell call & sell put
|
|
1> ask卖一价为0, P/L显示为 -
|
|
2> ask卖一价大于0, P/L =(Cost Price - ASK卖一价)*Contracts Quantity
|
|
四、保证金(Margin Ratio)
|
|
1> sell call 和 sell put:Margin =(Stock Price(行权价) * Option Multiplier(期权乘数)) * Margin Ratio(保证金比率) * Quantity
|
|
2> buy call 和 buy put:Margin = Open Filled Price(开仓价格) * Quantity(订单数量)
|
|
五、结算价值(Settlement Value)
|
|
1> Margin + P/L
|
|
*/
|
|
|
|
// OptionInrMessage
|
|
// @Description:
|
|
type OptionInrMessage struct {
|
|
Price string `json:"price"`
|
|
Bid string `json:"bid"`
|
|
Ask string `json:"ask"`
|
|
Code string `json:"code"`
|
|
BeforeClose string `json:"before_close"`
|
|
YesterdayClose string `json:"yesterday_close"`
|
|
CloseDate string `json:"option_date"`
|
|
}
|
|
|
|
// OptionInrSymbol
|
|
// @Description:
|
|
type OptionInrSymbol struct {
|
|
OpiMap chan []byte // 订单交易对 -- 用户下单通知订阅
|
|
OpiSetMap chan []byte // 订单交易对 -- 用户盘前|盘后行情订阅
|
|
OpiMapSymbol sync.Map // 订阅交易簿 -- 过滤重复
|
|
OpiSetMapSymbol sync.Map // 订阅交易簿 -- 过滤重复
|
|
}
|
|
|
|
// InitCacheSymbolOptionInr
|
|
//
|
|
// @Description:
|
|
// @param ctx
|
|
// @param uo
|
|
func InitCacheSymbolOptionInr(ctx context.Context, uo *Data) {
|
|
for {
|
|
thaList, err := GetBotStockOptionInrListByStockId(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 := Reds.HExists(context.Background(), setting.MarketOptionInr, value).Result()
|
|
if err != nil {
|
|
applogger.Error("%v InitCacheSymbolOptionInr.MarketOptionInr.HExists:%v", common.ErrOptionInr, err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
if !checkBool {
|
|
if err := Reds.HSet(context.Background(), setting.MarketOptionInr, value, value).Err(); err != nil {
|
|
applogger.Error("%v InitCacheSymbolOptionInr.MarketOptionInr.HSet:%v", common.ErrOptionInr, err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
}
|
|
if !flags.CheckSetting {
|
|
applogger.Info("初始化印度期权股票代码:%v", value)
|
|
}
|
|
}
|
|
|
|
time.Sleep(10 * time.Second)
|
|
}
|
|
}
|
|
|
|
// InitSubscribeOptionInr
|
|
//
|
|
// @Description: 状态机加载行情 - 订单表预加载
|
|
// @param ctx
|
|
// @param uo
|
|
// @param shareTha
|
|
func InitSubscribeOptionInr(OptionInr *OptionInrSymbol) {
|
|
for {
|
|
listSpots, err := LoadLRangeList(setting.AdminOptionInrSubscribe)
|
|
if err != nil {
|
|
applogger.Error("%v InitSubscribeOptionInr.LoadLRangeList:%v", common.ErrOptionInr, err)
|
|
return
|
|
}
|
|
|
|
for _, value := range listSpots {
|
|
var entrust option.OptionInrTallyCache
|
|
if err = json.Unmarshal([]byte(value), &entrust); err != nil {
|
|
applogger.Error("%v InitSubscribeOptionInr.Unmarshal:%v", common.ErrOptionInr, err)
|
|
continue
|
|
}
|
|
_, ok := OptionInr.OpiMapSymbol.Load(entrust.Order.StockCode)
|
|
if ok {
|
|
continue
|
|
}
|
|
OptionInr.OpiMap <- []byte(entrust.Order.StockCode)
|
|
}
|
|
|
|
time.Sleep(20 * time.Second)
|
|
}
|
|
}
|
|
|
|
// SubscriptionDataInformation
|
|
//
|
|
// @Description: 循环处理数据
|
|
// @param ctx
|
|
func SubscriptionDataInformation(ctx context.Context) {
|
|
for {
|
|
optionInr.OpiMapSymbol.Range(func(key, value interface{}) bool {
|
|
topIc, ok := key.(string)
|
|
if ok {
|
|
symbolStr := utils.ExtractSubstringBeforeFirstDigit(topIc)
|
|
_ = OptionInrMessageSet(symbolStr, topIc)
|
|
}
|
|
return true
|
|
})
|
|
|
|
time.Sleep(600 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
// SubscribeOptionInr
|
|
//
|
|
// @Description: 期权-印度股订阅
|
|
// @param ctx
|
|
// @param uo
|
|
// @param shareIdn
|
|
func SubscribeOptionInr(ctx context.Context, uo *Data, optionInr *OptionInrSymbol) {
|
|
for {
|
|
select {
|
|
case symbol, _ := <-optionInr.OpiMap:
|
|
// 期权标识:BEL20240425216000PE
|
|
topIc := string(symbol)
|
|
// 构造股票(BEL)
|
|
symbolStr := utils.ExtractSubstringBeforeFirstDigit(topIc)
|
|
// 处理重复订阅的情况
|
|
_, ok := optionInr.OpiMapSymbol.Load(topIc)
|
|
if ok {
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
// 将订阅的主题写入Redis的hot-cache列表
|
|
checkBool, err := Reds.HExists(context.Background(), setting.MarketOptionInr, symbolStr).Result()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if !checkBool {
|
|
if err := Reds.HSet(context.Background(), setting.MarketOptionInr, symbolStr, symbolStr).Err(); err != nil {
|
|
applogger.Error("%v SubscribeOptionInr.MarketOptionInr.HSet:%v", common.ErrOptionInr, err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
}
|
|
// 获取设置价格
|
|
if err := OptionInrMessageSet(symbolStr, topIc); err != nil {
|
|
applogger.Error("OptionInrMessageSet err:%v", topIc)
|
|
continue
|
|
}
|
|
// 将订阅的主题存入map中,用于判断是否重复订阅
|
|
optionInr.OpiMapSymbol.Store(topIc, topIc)
|
|
default:
|
|
Reds.Ping(ctx) // 如果没有消息,发送 PING 命令以维护连接
|
|
time.Sleep(10 * time.Second)
|
|
}
|
|
}
|
|
}
|
|
|
|
// OptionInrMessageSet
|
|
//
|
|
// @Description: 设置股票交易价格|买一卖一价格|闭盘价格
|
|
// @param topIc
|
|
// @return error
|
|
func OptionInrMessageSet(symbolStr, topIc string) error {
|
|
// 查询订单
|
|
keyCache := fmt.Sprintf("%v%v", flags.CountryOptionInr, symbolStr)
|
|
msg, err := Reds.HGet(context.Background(), keyCache, topIc).Result()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// 交易数据解析
|
|
var subMsg OptionInrMessage
|
|
if err = json.Unmarshal([]byte(msg), &subMsg); err != nil {
|
|
applogger.Error("%v SubscribeOptionInr.Unmarshal:%v", common.ErrOptionInr, err)
|
|
close(optionInr.OpiMap)
|
|
return err
|
|
}
|
|
// 处理订阅实时行情数据(订阅Key|交易价格|买一价|卖一价)
|
|
SubscribeOptionInrPrice(subMsg, topIc)
|
|
|
|
return nil
|
|
}
|
|
|
|
// SubscribeOptionInrPrice
|
|
//
|
|
// @Description: 期权-订阅获取印度股实时价格或者[盘前|盘后]设置价格
|
|
// @param setPrice
|
|
// @param symbolStr
|
|
// @param check
|
|
func SubscribeOptionInrPrice(optionInr OptionInrMessage, topIc string) {
|
|
// 交易类型: 期权最新价格-0,期权买一价-1,期权卖一价-2
|
|
// 缓存期权交易价格
|
|
keyPrice := publicData.SymbolCache(flags.Opi, topIc, flags.OptionPrice)
|
|
if err := memory.OptionInrCache.Set(keyPrice, []byte(optionInr.Price)); err != nil {
|
|
applogger.Error("%v SubscribeOptionInrPrice.OptionInrCache.Set.price:%v", common.ErrOptionInr, err)
|
|
}
|
|
// 缓存期权买一价格
|
|
keyBid := publicData.SymbolCache(flags.Opi, topIc, flags.OptionBid)
|
|
if err := memory.OptionInrBid.Set(keyBid, []byte(optionInr.Bid)); err != nil {
|
|
applogger.Error("%v SubscribeOptionInrPrice.OptionInrBid.Set.price:%v", common.ErrOptionInr, err)
|
|
}
|
|
// 缓存期权卖一价格
|
|
keyAsk := publicData.SymbolCache(flags.Opi, topIc, flags.OptionAsk)
|
|
if err := memory.OptionInrAsk.Set(keyAsk, []byte(optionInr.Ask)); err != nil {
|
|
applogger.Error("%v SubscribeOptionInrPrice.OptionInrAsk.Set.price:%v", common.ErrOptionInr, err)
|
|
}
|
|
|
|
// 设置闭盘价格
|
|
var price decimal.Decimal
|
|
closeStr := utils.ReplaceStr(optionInr.Price) == ""
|
|
yesterdayStr := utils.ReplaceStr(optionInr.YesterdayClose) == ""
|
|
beforeStr := utils.ReplaceStr(optionInr.BeforeClose) == ""
|
|
if closeStr {
|
|
optionInr.Price = decimal.Zero.String()
|
|
}
|
|
if yesterdayStr {
|
|
optionInr.YesterdayClose = decimal.Zero.String()
|
|
}
|
|
if beforeStr {
|
|
optionInr.BeforeClose = decimal.Zero.String()
|
|
}
|
|
closePrice := decimal.RequireFromString(optionInr.Price)
|
|
yesterdayClosePrice := decimal.RequireFromString(optionInr.YesterdayClose)
|
|
beforeClose := decimal.RequireFromString(optionInr.BeforeClose)
|
|
// 判定如果close为zero则取值yesterdayClosePrice,否取closePrice
|
|
if closePrice.IsZero() {
|
|
if !yesterdayClosePrice.IsZero() {
|
|
price = yesterdayClosePrice
|
|
}
|
|
} else {
|
|
price = closePrice
|
|
}
|
|
// 判定如果price为zero则取值beforeClose值,否取price
|
|
if price.IsZero() {
|
|
if !beforeClose.IsZero() {
|
|
price = beforeClose
|
|
}
|
|
}
|
|
// 闭盘价格
|
|
closeKey := publicData.SymbolCache(flags.Opi, topIc, flags.TradeTypeClosePrice)
|
|
if err := memory.OptionInrClosePrice.Set(closeKey, []byte(price.String())); err != nil {
|
|
applogger.Error("%v OptionInrClosePrice.Set.price:%v", common.ErrOptionInr, err)
|
|
}
|
|
|
|
if !flags.CheckSetting {
|
|
applogger.Info("期权股票交易代码:%v,交易价格:%v,买一价:%v,卖一价:%v,闭盘价:%v", topIc, optionInr.Price, optionInr.Bid, optionInr.Ask, price)
|
|
}
|
|
}
|
|
|
|
// OrderSubAdminOptionInrSubscribeBySum
|
|
//
|
|
// @Description: 期权-持仓订单浮动盈亏计算
|
|
// @param ctx
|
|
// @param uo
|
|
func OrderSubAdminOptionInrSubscribeBySum(uo *Data) {
|
|
for {
|
|
topIc := setting.AdminOptionInrSubscribe
|
|
hashMap, err := Reds.HGetAll(context.Background(), topIc).Result()
|
|
if err != nil {
|
|
applogger.Error("OrderSubAdminOptionInrSubscribeBySum.HGetAll:%v", err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
var hashList []option.OptionInrTallyCache
|
|
for _, value := range hashMap {
|
|
var msg option.OptionInrTallyCache
|
|
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 = Reds.HDel(context.Background(), topIc, msg.OrderId).Err()
|
|
if err != nil {
|
|
applogger.Error("OrderSubAdminOptionInrSubscribeBySum.HDel:%v", err)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
applogger.Info("统计印度期权股数据量统计:%v", len(hashList))
|
|
// 统计印度股持仓订单浮动盈亏
|
|
priceSum := decimal.Zero
|
|
for _, value := range hashList {
|
|
orderModel := optionData.OptionInrOrderProcessing(1, value)
|
|
if orderModel != nil {
|
|
if len(orderModel.Price) == 0 || len(orderModel.OpenPrice) == 0 {
|
|
continue
|
|
}
|
|
var newPrice, openPrice, orderNumber, subPrice, resultPrice decimal.Decimal
|
|
newPrice = decimal.RequireFromString(orderModel.Price) // 股票实时价格
|
|
openPrice = decimal.RequireFromString(orderModel.OpenPrice) // 订单开仓价格
|
|
orderNumber = decimal.RequireFromString(orderModel.OrderNumber) // 订单量
|
|
subPrice = OptionResultPrice(value.Order.TradeType, value.Order.TradingType, openPrice, newPrice) // 计算浮动盈亏
|
|
resultPrice = subPrice.Mul(orderNumber) // 计算订单浮动总盈亏
|
|
priceSum = priceSum.Add(resultPrice) // 累加盈亏统计
|
|
}
|
|
}
|
|
// 写入持仓订单浮动盈亏缓存
|
|
if err = memory.OptionInrFloating.Set(flags.FloatingOpi, []byte(priceSum.String())); err != nil {
|
|
applogger.Error("统计印度期权股持仓订单浮动盈亏错误:%v", err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
applogger.Info("统计印度期权股持仓订单浮动盈亏:%v", priceSum)
|
|
|
|
time.Sleep(3 * time.Second)
|
|
}
|
|
}
|
|
|
|
// OptionResultPrice
|
|
//
|
|
// @Description: 期权-浮动盈亏
|
|
// @param tradeType
|
|
// @param tradingType
|
|
// @param openPrice
|
|
// @param newPrice
|
|
// @return decimal.Decimal
|
|
func OptionResultPrice(tradeType, tradingType int64, openPrice, newPrice decimal.Decimal) decimal.Decimal {
|
|
//浮动盈亏(P/L)
|
|
//1>buy call & buy put
|
|
// 1> bid买一价为0, P/L显示为 -
|
|
// 2> bid买一价大于0, P/L =(bid买一价 - Cost Price)*Contracts Quantity
|
|
//2>sell call & sell put
|
|
// 1> ask卖一价为0, P/L显示为 -
|
|
// 2> ask卖一价大于0, P/L =(Cost Price - ASK卖一价)*Contracts Quantity
|
|
var subPrice decimal.Decimal
|
|
switch tradeType {
|
|
case flags.OptionCalls: // Call
|
|
switch tradingType {
|
|
case flags.OptionBuy: // buy - call
|
|
subPrice = newPrice.Sub(openPrice)
|
|
case flags.OptionSell: // sell - call
|
|
subPrice = openPrice.Sub(newPrice)
|
|
}
|
|
case flags.OptionPuts: // PUT
|
|
switch tradingType {
|
|
case flags.OptionBuy: // buy - put
|
|
subPrice = newPrice.Sub(openPrice)
|
|
case flags.OptionSell: // sell - put
|
|
subPrice = openPrice.Sub(newPrice)
|
|
}
|
|
default:
|
|
subPrice = decimal.Zero
|
|
}
|
|
return subPrice
|
|
}
|
|
|
|
// OptionInrTransactionEntrust
|
|
//
|
|
// @Description: 期权-印度股委托订单
|
|
// @param ctx
|
|
func OptionInrTransactionEntrust(ctx context.Context, uo *Data) {
|
|
for {
|
|
OptionInrTransactionCalculationEntrust(ctx, uo)
|
|
time.Sleep(400 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
// OptionInrTransactionCalculationEntrust
|
|
//
|
|
// @Description: 期权-印度股挂单缓存队列计算
|
|
// @param ctx
|
|
// @param uo
|
|
func OptionInrTransactionCalculationEntrust(ctx context.Context, uo *Data) {
|
|
var wg sync.WaitGroup
|
|
|
|
// 全局变量处理
|
|
if CheckGlobalTread(flags.OpiMarket) {
|
|
time.Sleep(5 * time.Second)
|
|
return
|
|
}
|
|
|
|
// 获取印度期权股挂单缓存列表
|
|
orderMap, err := Reds.HGetAll(context.Background(), setting.MarketOptionInrEntrust).Result()
|
|
if err != nil {
|
|
applogger.Error("%v OptionInrTransactionCalculationEntrust.HGetAll:%v", common.ErrOptionInr, err)
|
|
return
|
|
}
|
|
|
|
for _, value := range orderMap {
|
|
var msg = make(chan option.OptionInrTallyCache, 1)
|
|
var entrust option.OptionInrTallyCache
|
|
if err = json.Unmarshal([]byte(value), &entrust); err != nil {
|
|
applogger.Error("%v OptionInrTransactionCalculationEntrust.Unmarshal:%v", common.ErrOptionInr, err)
|
|
continue
|
|
}
|
|
// 到期时间小于当前时间-永远不给成交(撤单操作)
|
|
if CheckShareSystemTime(entrust.ClosingTime) {
|
|
applogger.Warn("%v 订单已超过到期时间不在成交:%v---%v", common.ErrOptionInr, entrust.Symbol, entrust.ClosingTime)
|
|
_, err = UpdateBotStockOptionInrCancelByOrderId(ctx, uo.mysqlDB, entrust.OrderId)
|
|
if err != nil {
|
|
applogger.Warn("%v 订单已超过到期时间不在成交,订单撤单失败:%v---%v", common.ErrOptionInr, entrust.Symbol, entrust.ClosingTime)
|
|
}
|
|
continue
|
|
}
|
|
// 期权交易价格|买一价|卖一价
|
|
var newPrice, bid, ask decimal.Decimal
|
|
newPrice, bid, ask, err = GetOptionInrPrice(entrust.Order.StockCode)
|
|
if err != nil {
|
|
applogger.Warn("%v OptionInrTransactionCalculationEntrust.GetOptionInrPrice:%v---%v", common.ErrOptionInr, entrust.Symbol, err)
|
|
continue
|
|
}
|
|
|
|
wg.Add(1)
|
|
go func(value string) {
|
|
var resultMsg option.OptionInrTallyCache
|
|
switch entrust.Order.DealType {
|
|
case flags.DealTypeLimited: // 限价-挂单
|
|
resultMsg = OptionInrConcurrentComputingEntrustLimited(&entrust, newPrice, bid, ask, &wg)
|
|
case flags.DealTypeMarket: // 市价-挂单(开盘即成交)
|
|
resultMsg = OptionInrConcurrentComputingEntrustMarket(&entrust, bid, ask, &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 = OptionInrLiquidationEntrust(ctx, &resultMsg); err != nil {
|
|
applogger.Warn("%v OptionInrTransactionCalculationEntrust.OptionInrLiquidationEntrust:%v", common.ErrOptionInr, err)
|
|
continue
|
|
}
|
|
// 写入持仓缓存列表
|
|
var byteStr []byte
|
|
byteStr, err = json.Marshal(resultMsg)
|
|
if err != nil {
|
|
applogger.Error("%v OptionInrTransactionCalculationEntrust.Marshal:%v", common.ErrOptionInr, err)
|
|
continue
|
|
}
|
|
|
|
// TODO: 写入持仓消息队列
|
|
//if err = uo.mqProducer.Entrust.PushNotice(byteStr); err != nil {
|
|
// applogger.Error("%v OptionInrTransactionCalculationEntrust.EntrustPushNotice:%v", common.ErrOptionInr, err)
|
|
// continue
|
|
//}
|
|
|
|
// 写入持仓队列缓存
|
|
if err = Reds.HSet(context.Background(), setting.MarketOptionInrPosition, resultMsg.OrderId, string(byteStr)).Err(); err != nil {
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wg.Wait()
|
|
applogger.Info("期权-印度股挂单并发计算执行完毕......")
|
|
}
|
|
|
|
// OptionInrConcurrentComputingEntrustLimited
|
|
//
|
|
// @Description: 期权-印度股挂单(限价|市价)缓存列表业务处理
|
|
// @param order
|
|
// @param newPrice
|
|
// @param wg
|
|
// @return option.OptionInrTallyCache
|
|
func OptionInrConcurrentComputingEntrustLimited(order *option.OptionInrTallyCache, newPrice, bid, ask decimal.Decimal, wg *sync.WaitGroup) option.OptionInrTallyCache {
|
|
var deleteCache bool
|
|
var dealPrice string
|
|
var status = order.Status // 订单状态
|
|
var limitPrice = decimal.RequireFromString(order.Order.LimitPrice) // 限价-价格
|
|
|
|
//限价单成交逻辑
|
|
//1>buy-call 和 buy-put 当卖一价(aks) <= 下单价 会成交即为下单价
|
|
//2>sell-call 和 sell-put 当买一价(bid) >= 下单价 会成交即为下单价
|
|
switch order.Order.TradeType {
|
|
case flags.OptionCalls: // call
|
|
switch order.Order.TradingType {
|
|
case flags.OptionBuy: // buy - call
|
|
if ask.Cmp(limitPrice) <= 0 {
|
|
deleteCache = true
|
|
dealPrice = limitPrice.String()
|
|
}
|
|
case flags.OptionSell: // sell - call
|
|
if bid.Cmp(limitPrice) >= 0 {
|
|
deleteCache = true
|
|
dealPrice = limitPrice.String()
|
|
}
|
|
}
|
|
case flags.OptionPuts: // put
|
|
switch order.Order.TradingType {
|
|
case flags.OptionBuy: // buy - put
|
|
if ask.Cmp(limitPrice) <= 0 {
|
|
deleteCache = true
|
|
dealPrice = limitPrice.String()
|
|
}
|
|
case flags.OptionSell: // sell - put
|
|
if bid.Cmp(limitPrice) >= 0 {
|
|
deleteCache = true
|
|
dealPrice = limitPrice.String()
|
|
}
|
|
}
|
|
}
|
|
|
|
if deleteCache {
|
|
order.Status = flags.Position
|
|
if err := Reds.HDel(context.Background(), setting.MarketOptionInrEntrust, order.OrderId).Err(); err != nil {
|
|
applogger.Error("%v OptionInrConcurrentComputingEntrustLimited.HDel:%v", common.ErrOptionInr, err)
|
|
order.Status = status
|
|
}
|
|
}
|
|
|
|
wg.Done()
|
|
return option.OptionInrTallyCache{
|
|
UserId: order.UserId, // 用户Id
|
|
OrderId: order.OrderId, // 订单Id
|
|
Symbol: order.Symbol, // 下单交易对
|
|
OpenPrice: dealPrice, // 开仓价格
|
|
Status: order.Status, // 订单状态
|
|
Order: order.Order, // 下单信息
|
|
ClosingTime: order.ClosingTime, // 平仓时间
|
|
}
|
|
}
|
|
|
|
// OptionInrConcurrentComputingEntrustMarket
|
|
//
|
|
// @Description: 期权-印度股市价下单进入挂单队列(休市)
|
|
// @param order
|
|
// @param newPrice
|
|
// @param wg
|
|
// @return option.OptionInrTallyCache
|
|
func OptionInrConcurrentComputingEntrustMarket(order *option.OptionInrTallyCache, bid, ask decimal.Decimal, wg *sync.WaitGroup) option.OptionInrTallyCache {
|
|
var deleteCache bool
|
|
var dealPrice string
|
|
var status = order.Status // 原始状态
|
|
//市价单交易
|
|
//1>buy-call 和 buy-put 以卖一价(ask)成交
|
|
//2>sell-call 和 sell-put 以买一价(bid)成交
|
|
switch order.Order.TradeType {
|
|
case flags.OptionCalls: // call
|
|
switch order.Order.TradingType {
|
|
case flags.OptionBuy: // buy - call
|
|
if !ask.IsZero() {
|
|
deleteCache = true
|
|
dealPrice = ask.String()
|
|
}
|
|
case flags.OptionSell: // sell - call
|
|
if !bid.IsZero() {
|
|
deleteCache = true
|
|
dealPrice = bid.String()
|
|
}
|
|
}
|
|
case flags.OptionPuts: // put
|
|
switch order.Order.TradingType {
|
|
case flags.OptionBuy: // buy - put
|
|
if !ask.IsZero() {
|
|
deleteCache = true
|
|
dealPrice = ask.String()
|
|
}
|
|
case flags.OptionSell: // sell - put
|
|
if !bid.IsZero() {
|
|
deleteCache = true
|
|
dealPrice = bid.String()
|
|
}
|
|
}
|
|
}
|
|
|
|
if deleteCache {
|
|
order.Status = flags.Position
|
|
if err := Reds.HDel(context.Background(), setting.MarketOptionInrEntrust, order.OrderId).Err(); err != nil {
|
|
applogger.Error("%v OptionInrConcurrentComputingEntrustMarket.HDel:%v", common.ErrOptionInr, err)
|
|
order.Status = status
|
|
}
|
|
}
|
|
|
|
wg.Done()
|
|
return option.OptionInrTallyCache{
|
|
UserId: order.UserId, // 用户Id
|
|
OrderId: order.OrderId, // 订单Id
|
|
Symbol: order.Symbol, // 下单交易对
|
|
OpenPrice: dealPrice, // 开仓价格
|
|
Status: order.Status, // 订单状态
|
|
Order: order.Order, // 下单信息
|
|
ClosingTime: order.ClosingTime, // 平仓时间
|
|
}
|
|
}
|
|
|
|
// OptionInrMqOpenBusiness
|
|
//
|
|
// @Description: TODO: 期权-印度股持仓消息队列
|
|
// @param ctx
|
|
// @param uo
|
|
func OptionInrMqOpenBusiness(ctx context.Context, uo *Data) {
|
|
go func() {
|
|
uo.mqConsumer.Entrust.ConsumerNotice()
|
|
}()
|
|
for {
|
|
select {
|
|
case message, ok := <-consumer.ConsumerEntrustMq.OptionInrMq:
|
|
if !ok {
|
|
time.Sleep(5 * time.Second)
|
|
applogger.Error("%v OptionInrMqOpenBusiness.OptionInrMq err....", common.ErrOptionInr)
|
|
continue
|
|
}
|
|
|
|
// 持仓订单缓存数据序列化解析
|
|
var resultMsg option.OptionInrTallyCache
|
|
if err := json.Unmarshal(message, &resultMsg); err != nil {
|
|
applogger.Error("%v OptionInrMqOpenBusiness.Unmarshal:%v", common.ErrOptionInr, err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
|
|
// 持仓平仓
|
|
if err := OptionInrLiquidationEntrust(ctx, &resultMsg); err != nil {
|
|
applogger.Error("%v OptionInrMqOpenBusiness.OptionInrLiquidationEntrust:%v", common.ErrOptionInr, err)
|
|
continue
|
|
}
|
|
default:
|
|
// TODO: 是否处理空队列缓存的情况
|
|
applogger.Error("这里没有监控到持仓mq队列消息.........")
|
|
time.Sleep(2 * time.Second)
|
|
}
|
|
}
|
|
}
|
|
|
|
// OptionInrLiquidationEntrust
|
|
//
|
|
// @Description: 期权-印度股挂单-->开仓业务处理
|
|
// @param ctx
|
|
// @param order
|
|
// @return error
|
|
func OptionInrLiquidationEntrust(ctx context.Context, order *option.OptionInrTallyCache) error {
|
|
// 1、开盘
|
|
err := OptionInrOpenOrder(ctx, Msql, order.UserId, order.OrderId, order.OpenPrice, order.Order)
|
|
if err != nil {
|
|
applogger.Error("%v OptionInrLiquidationEntrust.OptionInrOpenOrder:%v", common.ErrOptionInr, err)
|
|
return err
|
|
}
|
|
|
|
// 2、更新用户订阅缓存列表订单状态
|
|
updateKey := virtual.OrderIdListKey(setting.OptionInrSubscribe, order.UserId)
|
|
if err = UpdateOptionInrSubscribeHashStatusByOrderId(order.OrderId, updateKey, flags.Position, order.OpenPrice); err != nil {
|
|
applogger.Error("%v OptionInrLiquidationEntrust.Entrust.OptionInrSubscribe:%v", common.ErrOptionInr, err)
|
|
return err
|
|
}
|
|
|
|
// 3、更新管理员订阅缓存列表订单状态
|
|
if err = UpdateOptionInrSubscribeHashStatusByOrderId(order.OrderId, setting.AdminOptionInrSubscribe, flags.Position, order.OpenPrice); err != nil {
|
|
applogger.Error("%v OptionInrLiquidationEntrust.Entrust.AdminOptionInrSubscribe:%v", common.ErrOptionInr, err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// OptionInrTransactionPosition
|
|
//
|
|
// @Description: 期权-印度股持仓订单
|
|
// @param ctx
|
|
func OptionInrTransactionPosition(ctx context.Context) {
|
|
for {
|
|
OptionInrTransactionCalculationPosition(ctx)
|
|
time.Sleep(400 * time.Millisecond)
|
|
}
|
|
}
|
|
|
|
// OptionInrTransactionCalculationPosition
|
|
//
|
|
// @Description: 期权-印度股持仓缓存队列计算
|
|
// @param ctx
|
|
func OptionInrTransactionCalculationPosition(ctx context.Context) {
|
|
var wg sync.WaitGroup
|
|
|
|
// 判定是否交易
|
|
if CheckGlobalTread(flags.OpiMarket) {
|
|
time.Sleep(5 * time.Second)
|
|
return
|
|
}
|
|
|
|
// TODO: 获取IPO未支付订单缓存
|
|
userIdMap, _ := GetBotUserArrears(ctx)
|
|
|
|
// 持仓缓存列表
|
|
orderMap, err := Reds.HGetAll(context.Background(), setting.MarketOptionInrPosition).Result()
|
|
if err != nil {
|
|
applogger.Error("%v OptionInrTransactionCalculationPosition.HGetAll:%v", common.ErrOptionInr, err)
|
|
return
|
|
}
|
|
|
|
for _, value := range orderMap {
|
|
var msg = make(chan option.OptionInrTallyCache, 1)
|
|
var entrust option.OptionInrTallyCache
|
|
if err = json.Unmarshal([]byte(value), &entrust); err != nil {
|
|
applogger.Error("%v OptionInrTransactionCalculationPosition.Unmarshal:%v", common.ErrOptionInr, err)
|
|
continue
|
|
}
|
|
|
|
// TODO: 判定是否未IPO未支付订单-不能平仓
|
|
_, isOk := userIdMap[entrust.UserId]
|
|
if isOk {
|
|
continue
|
|
}
|
|
|
|
// 期权交易价格|买一价|卖一价
|
|
var newPrice, bid, ask decimal.Decimal
|
|
newPrice, bid, ask, err = GetOptionInrPrice(entrust.Order.StockCode)
|
|
if err != nil {
|
|
applogger.Warn("%v OptionInrTransactionCalculationPosition.Get:%v--%v", common.ErrOptionInr, entrust.Symbol, err)
|
|
continue
|
|
}
|
|
|
|
// 期权到期时间日内停盘前一个小时平仓
|
|
checkClosingTime := utils.TimeComparison(entrust.ClosingTime)
|
|
|
|
wg.Add(1)
|
|
go func(value string) {
|
|
resultMsg := OptionInrConcurrentComputingPosition(&entrust, newPrice, bid, ask, &wg, checkClosingTime)
|
|
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 OptionInrTransactionCalculationPosition.Marshal:%v", common.ErrOptionInr, err)
|
|
// continue
|
|
//}
|
|
//if err = uo.mqProducer.Position.PushNotice(byteStr); err != nil {
|
|
// applogger.Error("%v OptionInrTransactionCalculationPosition.DealPublish:%v", common.ErrOptionInr, err)
|
|
// continue
|
|
//}
|
|
|
|
if err = OptionInrLiquidationPosition(ctx, &resultMsg); err != nil {
|
|
applogger.Error("%v OptionInrTransactionCalculationPosition.OptionInrLiquidationPosition:%v", common.ErrOptionInr, err)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wg.Wait()
|
|
applogger.Info("期权-印度股持仓并发计算执行完毕......")
|
|
}
|
|
|
|
// OptionInrConcurrentComputingPosition
|
|
//
|
|
// @Description: 期权-印度股持仓缓存列表业务处理
|
|
// @param order
|
|
// @param newPrice
|
|
// @param wg
|
|
// @param checkFlattening
|
|
// @return option.OptionInrTallyCache
|
|
func OptionInrConcurrentComputingPosition(order *option.OptionInrTallyCache, newPrice, bid, ask decimal.Decimal, wg *sync.WaitGroup, checkClosingTime bool) option.OptionInrTallyCache {
|
|
var deleteCache bool
|
|
var openPrice = decimal.RequireFromString(order.OpenPrice) // 限价
|
|
var orderNumber = decimal.RequireFromString(order.Order.OrderNumber) // 仓位
|
|
|
|
// 下单判定设置(false无设置|true止盈止损)
|
|
_, stopWinPrice, stopLossPrice, _ := OptionInrVoteStopType(order.Order)
|
|
|
|
// 平仓
|
|
//1>buy-call 和 buy-put 平仓价格以买一价(bid)成交
|
|
//2>sell-call 和 sell-put 平仓价格以卖一价(ask)成交
|
|
|
|
// 期权:止盈止损
|
|
//一、call-buy 和 put-buy
|
|
//1>止盈:买一价 >= 止盈价
|
|
//2>止损:卖一价 <= 止损价
|
|
//二、call-sell 和 put-sell
|
|
//1>止盈:卖一价 <= 止盈价
|
|
//2>止损:买一价 >= 止损价
|
|
dealPrice, sellShort, checkBool := ClosePriceStopWinOrStopLossPrice(order.Order.TradingType, newPrice, stopWinPrice, stopLossPrice, bid, ask, openPrice, orderNumber)
|
|
|
|
/* 强行平仓(做多|做空)
|
|
1、做多:(最新成交价-开仓成交价)*仓位
|
|
2、做空:(开仓成交价-最新成交价)*仓位
|
|
3、当浮动盈亏 >= 保证金的70%订单强行平仓
|
|
*/
|
|
if sellShort.IsNegative() {
|
|
//保证金(Margin Ratio)
|
|
//1> buy call 和 buy put:Margin = Open Filled Price(当前价格) * Quantity(订单数量)
|
|
//2> sell call 和 sell put:Margin = (Stock Price(行权价) * Option Multiplier(期权乘数)) * Margin Ratio(保证金比率) * Quantity(订单数量)
|
|
var orderAmount, strikePrice, multiplier, ratio decimal.Decimal
|
|
ratio = decimal.RequireFromString(order.Order.Ratio)
|
|
multiplier = decimal.RequireFromString(order.Order.Multiplier)
|
|
strikePrice = decimal.RequireFromString(order.Order.StrikePrice)
|
|
switch order.Order.TradeType {
|
|
case flags.OptionCalls: // CallS
|
|
switch order.Order.TradingType {
|
|
case flags.OptionBuy: // buy
|
|
orderAmount = openPrice.Mul(orderNumber)
|
|
case flags.OptionSell: // sell
|
|
orderAmount = strikePrice.Mul(multiplier).Mul(ratio).Mul(orderNumber)
|
|
}
|
|
case flags.OptionPuts: // PUTS
|
|
switch order.Order.TradingType {
|
|
case flags.OptionBuy: // buy
|
|
orderAmount = openPrice.Mul(orderNumber)
|
|
case flags.OptionSell: // sell
|
|
orderAmount = strikePrice.Mul(multiplier).Mul(ratio).Mul(orderNumber)
|
|
}
|
|
default:
|
|
|
|
}
|
|
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
|
|
dealPrice = newPrice // 平仓价格
|
|
}
|
|
}
|
|
|
|
// 符合: 1、强平条件 2、到达到期时间
|
|
if checkBool || checkClosingTime {
|
|
deleteCache = true
|
|
order.Status = flags.Close
|
|
}
|
|
// 清理持仓缓存订单
|
|
if deleteCache {
|
|
if err := Reds.HDel(context.Background(), setting.MarketOptionInrPosition, order.OrderId).Err(); err != nil {
|
|
applogger.Error("%v OptionInrConcurrentComputingPosition.Position.HDel:%v", common.ErrOptionInr, err)
|
|
}
|
|
}
|
|
|
|
wg.Done()
|
|
return option.OptionInrTallyCache{
|
|
UserId: order.UserId, // 用户Id
|
|
OrderId: order.OrderId, // 订单Id
|
|
Symbol: order.Symbol, // 下单交易对
|
|
ClosingPrice: dealPrice.String(), // 平仓价格
|
|
Status: order.Status, // 订单状态
|
|
Order: order.Order, // 下单信息
|
|
ClosingTime: order.ClosingTime, // 平仓时间
|
|
}
|
|
}
|
|
|
|
// ClosePriceStopWinOrStopLossPrice
|
|
//
|
|
// @Description: 持仓平仓-止盈止损设置判定
|
|
// @param tradingType
|
|
// @param newPrice
|
|
// @param stopWinPrice
|
|
// @param stopLossPrice
|
|
// @param bid
|
|
// @param ask
|
|
// @param openPrice
|
|
// @param orderNumber
|
|
// @return decimal.Decimal
|
|
// @return decimal.Decimal
|
|
// @return bool
|
|
func ClosePriceStopWinOrStopLossPrice(tradingType int64, newPrice, stopWinPrice, stopLossPrice, bid, ask, openPrice, orderNumber decimal.Decimal) (decimal.Decimal, decimal.Decimal, bool) {
|
|
var checkBool bool
|
|
var dealPrice, sellShort decimal.Decimal
|
|
|
|
switch tradingType {
|
|
case flags.OptionBuy: // call - buy
|
|
if !stopWinPrice.IsZero() {
|
|
if bid.Cmp(stopWinPrice) >= 0 {
|
|
checkBool = true
|
|
dealPrice = newPrice
|
|
}
|
|
}
|
|
if !stopLossPrice.IsZero() {
|
|
if ask.Cmp(stopLossPrice) <= 0 {
|
|
checkBool = true
|
|
dealPrice = newPrice
|
|
}
|
|
}
|
|
if !newPrice.IsZero() {
|
|
if !checkBool { // 强行平仓(做多)
|
|
sellShort = newPrice.Sub(openPrice).Mul(orderNumber)
|
|
}
|
|
}
|
|
case flags.OptionSell: // call -sell
|
|
if !stopWinPrice.IsZero() {
|
|
if ask.Cmp(stopWinPrice) <= 0 {
|
|
checkBool = true
|
|
dealPrice = newPrice
|
|
}
|
|
}
|
|
if !stopLossPrice.IsZero() {
|
|
if bid.Cmp(stopLossPrice) >= 0 {
|
|
checkBool = true
|
|
dealPrice = newPrice
|
|
}
|
|
}
|
|
if !newPrice.IsZero() {
|
|
if !checkBool { // 强行平仓(做空)
|
|
sellShort = openPrice.Sub(newPrice).Mul(orderNumber)
|
|
}
|
|
}
|
|
}
|
|
return dealPrice, sellShort, checkBool
|
|
}
|
|
|
|
// OptionInrMqClosingBusiness
|
|
//
|
|
// @Description: TODO: 期权-印度股平仓消息队列
|
|
// @param ctx
|
|
// @param uo
|
|
func OptionInrMqClosingBusiness(ctx context.Context, uo *Data) {
|
|
go func() {
|
|
uo.mqConsumer.Position.ConsumerNotice()
|
|
}()
|
|
for {
|
|
select {
|
|
case message, ok := <-consumer.ConsumerPositionMq.OptionInrMq:
|
|
if !ok {
|
|
time.Sleep(5 * time.Second)
|
|
applogger.Error("%v OptionInrMqClosingBusiness.OptionInrMq err....", common.ErrOptionInr)
|
|
continue
|
|
}
|
|
applogger.Info("接收到平仓信息:%v", string(message))
|
|
|
|
// 持仓订单缓存数据序列化解析
|
|
var resultMsg option.OptionInrTallyCache
|
|
if err := json.Unmarshal(message, &resultMsg); err != nil {
|
|
applogger.Error("%v OptionInrMqClosingBusiness.Unmarshal:%v", common.ErrOptionInr, err)
|
|
time.Sleep(5 * time.Second)
|
|
continue
|
|
}
|
|
|
|
// 持仓平仓
|
|
if err := OptionInrLiquidationPosition(ctx, &resultMsg); err != nil {
|
|
applogger.Error("%v OptionInrMqClosingBusiness.OptionInrLiquidationPosition:%v", common.ErrOptionInr, err)
|
|
continue
|
|
}
|
|
default:
|
|
// TODO: 是否处理空队列缓存的情况
|
|
time.Sleep(2 * time.Second)
|
|
}
|
|
}
|
|
}
|
|
|
|
// OptionInrLiquidationPosition
|
|
//
|
|
// @Description: 期权-印度股持仓-->平仓业务处理
|
|
// @param ctx
|
|
// @param order
|
|
// @return error
|
|
func OptionInrLiquidationPosition(ctx context.Context, order *option.OptionInrTallyCache) error {
|
|
// 1、平仓操作
|
|
err := OptionInrClosingOrder(ctx, Msql, order.OrderId, order.ClosingPrice, order.Order)
|
|
if err != nil {
|
|
applogger.Error("%v OptionInrLiquidationPosition.OptionInrClosingOrder:%v", common.ErrOptionInr, err)
|
|
return err
|
|
}
|
|
|
|
// 2、平仓更新用户订阅订单状态
|
|
userSubKey := virtual.OrderIdListKey(setting.OptionInrSubscribe, order.UserId)
|
|
if err = UpdateOptionInrSubscribeHashStatusByOrderId(order.OrderId, userSubKey, flags.Close, flags.SetNull); err != nil {
|
|
applogger.Error("%v OptionInrLiquidationPosition.Position.OptionInrSubscribe:%v", common.ErrOptionInr, err)
|
|
return err
|
|
}
|
|
|
|
// 3、平仓更新管理员订阅订单状态
|
|
if err = UpdateOptionInrSubscribeHashStatusByOrderId(order.OrderId, setting.AdminOptionInrSubscribe, flags.Close, flags.SetNull); err != nil {
|
|
applogger.Error("%v OptionInrLiquidationPosition.Position.AdminOptionInrSubscribe:%v", common.ErrOptionInr, err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// OptionInrVoteStopType
|
|
//
|
|
// @Description: 期权-印度股交易下单判定
|
|
// @param order
|
|
// @return bool
|
|
// @return decimal.Decimal
|
|
// @return decimal.Decimal
|
|
// @return error
|
|
func OptionInrVoteStopType(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
|
|
if len(order.StopWinPrice) != 0 {
|
|
stopWinPrice = decimal.RequireFromString(order.StopWinPrice)
|
|
}
|
|
if len(order.StopLossPrice) != 0 {
|
|
stopLossPrice = decimal.RequireFromString(order.StopLossPrice)
|
|
}
|
|
default:
|
|
return checkBool, stopWinPrice, stopLossPrice, flags.ErrContractThirteen
|
|
}
|
|
|
|
return checkBool, stopWinPrice, stopLossPrice, nil
|
|
}
|
|
|
|
// GetOptionInrPrice
|
|
//
|
|
// @Description: 期权-印度股股票价格
|
|
// @param symbol
|
|
// @return decimal.Decimal
|
|
// @return decimal.Decimal
|
|
// @return decimal.Decimal
|
|
// @return error
|
|
func GetOptionInrPrice(stockCode string) (decimal.Decimal, decimal.Decimal, decimal.Decimal, error) {
|
|
var err error
|
|
var priceByte, priceBid, priceAsk []byte
|
|
var newPrice, bidPrice, askPrice decimal.Decimal
|
|
|
|
// 交易价格
|
|
priceKey := publicData.SymbolCache(flags.Opi, stockCode, flags.OptionPrice)
|
|
priceByte, err = memory.GetOptionInrCache(priceKey)
|
|
if err != nil {
|
|
return decimal.Decimal{}, decimal.Decimal{}, decimal.Decimal{}, err
|
|
}
|
|
newPrice, _ = decimal.NewFromString(string(priceByte))
|
|
|
|
// 买一价格
|
|
bidKey := publicData.SymbolCache(flags.Opi, stockCode, flags.OptionBid)
|
|
priceBid, err = memory.GetOptionInrBid(bidKey)
|
|
if err != nil {
|
|
return decimal.Decimal{}, decimal.Decimal{}, decimal.Decimal{}, err
|
|
}
|
|
bidPrice, _ = decimal.NewFromString(string(priceBid))
|
|
|
|
// 卖一价格
|
|
askKey := publicData.SymbolCache(flags.Opi, stockCode, flags.OptionAsk)
|
|
priceAsk, err = memory.GetOptionInrAsk(askKey)
|
|
if err != nil {
|
|
return decimal.Decimal{}, decimal.Decimal{}, decimal.Decimal{}, err
|
|
}
|
|
askPrice, _ = decimal.NewFromString(string(priceAsk))
|
|
|
|
applogger.Info("optionInrCode:%v,optionInrPrice:%v,optionInrBid:%v,optionInrAsk:%v", stockCode, newPrice, bidPrice, askPrice)
|
|
|
|
return newPrice, bidPrice, askPrice, nil
|
|
}
|
|
|
|
// GetOptionInrStrike
|
|
//
|
|
// @Description: 期权-印度获取股票行权价
|
|
// @param symbol
|
|
// @param Expiry
|
|
// @return decimal.Decimal
|
|
// @return error
|
|
func GetOptionInrStrike(symbol, Expiry string) (decimal.Decimal, error) {
|
|
var err error
|
|
var priceByte []byte
|
|
key := publicData.SymbolCache(flags.OpiStk, symbol, flags.TradeTypePrice)
|
|
priceByte, err = memory.GetOptionInrStrike(key)
|
|
if err != nil {
|
|
return decimal.Decimal{}, err
|
|
}
|
|
|
|
var strikePrice map[string]decimal.Decimal
|
|
if err = json.Unmarshal(priceByte, &strikePrice); err != nil {
|
|
return decimal.Decimal{}, err
|
|
}
|
|
|
|
var strike decimal.Decimal
|
|
for day, value := range strikePrice {
|
|
if day == Expiry {
|
|
strike = value
|
|
}
|
|
}
|
|
|
|
applogger.Info("optionInrCode:%v,topIc:%v,optionInrStrikePrice:%v", symbol, key, strikePrice)
|
|
|
|
return strike, nil
|
|
}
|
|
|