2 Star 2 Fork 0

trackertrader / goctp

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
trade_win.go 27.70 KB
一键复制 编辑 原始数据 按行查看 历史
wulengbing@163.com 提交于 2022-01-28 11:15 . modify
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
package win
import (
"fmt"
"gitee.com/graverchain/goctp"
ctp "gitee.com/graverchain/goctp/ctpdefine"
"golang.org/x/text/encoding/simplifiedchinese"
"strings"
"sync"
"time"
)
// Trade 交易接口
type Trade struct {
t *trade
// 密码
passWord string
// 判断是否自己的委托用
sessionID int
InvestorID string // 帐号
BrokerID string // 经纪商
TradingDay string // 交易日
Instruments sync.Map // 合约列表
InstrumentStatus sync.Map // 合约状态
Positions sync.Map // 持仓列表
Orders sync.Map // 委托
Trades sync.Map // 成交
ordersn4Order sync.Map // ordersn 对应的 Order
// 帐户权益
Account *goctp.AccountField
// 登录成功
IsLogin bool
// 循环查询
qryTicker *time.Ticker
onFrontConnected goctp.OnFrontConnectedType
onFrontDisConnected goctp.OnFrontDisConnectedType
onRspUserLogin goctp.OnRspUserLoginType
onRtnOrder goctp.OnRtnOrderType
onRtnCancel goctp.OnRtnOrderType
onErrRtnOrder goctp.OnRtnErrOrderType
onErrAction goctp.OnRtnErrActionType
onRtnTrade goctp.OnRtnTradeType
onRtnInstrument goctp.OnRtnInstrumentType
onRtnInstrumentStatus goctp.OnRtnInstrumentStatusType
onRtnPosition goctp.OnRtnPositionType
onRtnAccount goctp.OnRtnAccountType
cntOrder int
}
// NewTrade 交易接口实例
func NewTrade() *Trade {
t := new(Trade)
// 初始化变量
t.IsLogin = false
t.Account = &goctp.AccountField{}
t.t = newTrade()
t.t.regOnFrontConnected(t.onConnected)
t.t.regOnFrontDisconnected(t.onDisConnected)
t.t.regOnRspAuthenticate(t.onAuth)
t.t.regOnRspSettlementInfoConfirm(t.onSettlement)
t.t.regOnRspUserLogin(t.onLogin)
t.t.regOnRspQryInstrument(t.onInstrument)
t.t.regOnRspQryTradingAccount(t.onAccount)
t.t.regOnRspQryInvestorPosition(t.onPosition)
t.t.regOnRtnOrder(t.onOrder)
t.t.regOnErrRtnOrderInsert(t.onErrOrder)
t.t.regOnRtnTrade(t.onTrade)
t.t.regOnRtnInstrumentStatus(t.onStatus)
t.t.regOnErrRtnOrderAction(t.onErrRtnOrderAction)
return t
}
// ********************** 主调函数 ************************
// Release 接口销毁处理
func (t *Trade) Release() {
t.IsLogin = false
t.onDisConnected(0)
if nil != t.t {
t.t.Release()
}
}
// ReqConnect 连接
func (t *Trade) ReqConnect(addr string) {
t.t.RegisterFront(addr)
t.t.SubscribePrivateTopic(ctp.THOST_TERT_RESUME)
t.t.SubscribePublicTopic(ctp.THOST_TERT_RESUME)
t.t.Init()
}
// ReqLogin 登录
func (t *Trade) ReqLogin(investor, pwd, broker, appID, authCode string) {
t.InvestorID = investor
t.passWord = pwd
t.BrokerID = broker
f := ctp.CThostFtdcReqAuthenticateField{}
copy(f.BrokerID[:], broker)
copy(f.UserID[:], investor)
copy(f.AppID[:], appID)
copy(f.AuthCode[:], authCode)
t.t.ReqAuthenticate(f)
}
// ReqOrderInsert 限价委托
func (t *Trade) ReqOrderInsert(requestid int32, ordersn string, instrument string, buySell goctp.DirectionType, openClose goctp.OffsetFlagType, price float64, volume int) string {
f := ctp.CThostFtdcInputOrderField{}
copy(f.BrokerID[:], t.BrokerID)
if info, ok := t.Instruments.Load(instrument); ok {
copy(f.ExchangeID[:], info.(*goctp.InstrumentField).ExchangeID)
}
copy(f.UserID[:], t.InvestorID)
copy(f.InvestorID[:], t.InvestorID)
copy(f.AccountID[:], t.InvestorID)
f.IsAutoSuspend = ctp.TThostFtdcBoolType(0)
f.IsSwapOrder = ctp.TThostFtdcBoolType(0)
f.ForceCloseReason = ctp.THOST_FTDC_FCC_NotForceClose
// 参数赋值
copy(f.OrderRef[:], ordersn)
copy(f.InstrumentID[:], instrument)
f.RequestID = ctp.TThostFtdcRequestIDType(requestid)
f.Direction = ctp.TThostFtdcDirectionType(buySell)
f.CombOffsetFlag[0] = byte(openClose)
f.CombHedgeFlag[0] = byte(goctp.HedgeFlagSpeculation)
// 不同类型的Order
f.OrderPriceType = ctp.THOST_FTDC_OPT_LimitPrice
f.TimeCondition = ctp.THOST_FTDC_TC_GFD
f.VolumeCondition = ctp.THOST_FTDC_VC_AV
f.ContingentCondition = ctp.THOST_FTDC_CC_Immediately
f.LimitPrice = ctp.TThostFtdcPriceType(price)
f.VolumeTotalOriginal = ctp.TThostFtdcVolumeType(volume)
t.t.ReqOrderInsert(f)
return fmt.Sprintf("%d_%s_%d", t.sessionID, goctp.Bytes2String(f.OrderRef[:]), requestid)
}
// ReqOrderInsertMarket 市价委托
func (t *Trade) ReqOrderInsertMarket(requestid int32, ordersn string, instrument string, buySell goctp.DirectionType, openClose goctp.OffsetFlagType, volume int) string {
f := ctp.CThostFtdcInputOrderField{}
copy(f.BrokerID[:], t.BrokerID)
if info, ok := t.Instruments.Load(instrument); ok {
copy(f.ExchangeID[:], info.(*goctp.InstrumentField).ExchangeID)
}
copy(f.UserID[:], t.InvestorID)
copy(f.InvestorID[:], t.InvestorID)
copy(f.AccountID[:], t.InvestorID)
f.IsAutoSuspend = ctp.TThostFtdcBoolType(0)
f.IsSwapOrder = ctp.TThostFtdcBoolType(0)
f.ForceCloseReason = ctp.THOST_FTDC_FCC_NotForceClose
// 参数赋值
copy(f.OrderRef[:], ordersn)
copy(f.InstrumentID[:], instrument)
f.RequestID = ctp.TThostFtdcRequestIDType(requestid)
f.Direction = ctp.TThostFtdcDirectionType(buySell)
f.CombOffsetFlag[0] = byte(openClose)
f.CombHedgeFlag[0] = byte(goctp.HedgeFlagSpeculation)
// 不同类型的Order
f.OrderPriceType = ctp.THOST_FTDC_OPT_AnyPrice
f.TimeCondition = ctp.THOST_FTDC_TC_IOC
f.VolumeCondition = ctp.THOST_FTDC_VC_AV
f.ContingentCondition = ctp.THOST_FTDC_CC_Immediately
f.LimitPrice = ctp.TThostFtdcPriceType(0)
f.VolumeTotalOriginal = ctp.TThostFtdcVolumeType(volume)
t.t.ReqOrderInsert(f)
return fmt.Sprintf("%d_%s_%d", t.sessionID, goctp.Bytes2String(f.OrderRef[:]), requestid)
}
// ReqOrderInsertFOK FOK委托[部成撤单]
func (t *Trade) ReqOrderInsertFOK(requestid int32, ordersn string, instrument string, buySell goctp.DirectionType, openClose goctp.OffsetFlagType, price float64, volume int) string {
f := ctp.CThostFtdcInputOrderField{}
copy(f.BrokerID[:], t.BrokerID)
if info, ok := t.Instruments.Load(instrument); ok {
copy(f.ExchangeID[:], info.(*goctp.InstrumentField).ExchangeID)
}
copy(f.UserID[:], t.InvestorID)
copy(f.InvestorID[:], t.InvestorID)
copy(f.AccountID[:], t.InvestorID)
f.IsAutoSuspend = ctp.TThostFtdcBoolType(0)
f.IsSwapOrder = ctp.TThostFtdcBoolType(0)
f.ForceCloseReason = ctp.THOST_FTDC_FCC_NotForceClose
// 参数赋值
copy(f.OrderRef[:], ordersn)
copy(f.InstrumentID[:], instrument)
f.RequestID = ctp.TThostFtdcRequestIDType(requestid)
f.Direction = ctp.TThostFtdcDirectionType(buySell)
f.CombOffsetFlag[0] = byte(openClose)
f.CombHedgeFlag[0] = byte(goctp.HedgeFlagSpeculation)
// 不同类型的Order
f.OrderPriceType = ctp.THOST_FTDC_OPT_LimitPrice
f.TimeCondition = ctp.THOST_FTDC_TC_GFD
f.VolumeCondition = ctp.THOST_FTDC_VC_CV
f.ContingentCondition = ctp.THOST_FTDC_CC_Immediately
f.LimitPrice = ctp.TThostFtdcPriceType(price)
f.VolumeTotalOriginal = ctp.TThostFtdcVolumeType(volume)
t.t.ReqOrderInsert(f)
return fmt.Sprintf("%d_%s_%d", t.sessionID, goctp.Bytes2String(f.OrderRef[:]), requestid)
}
// ReqOrderInsertFAK FAK委托[全成or撤单]
func (t *Trade) ReqOrderInsertFAK(requestid int32, ordersn string, instrument string, buySell goctp.DirectionType, openClose goctp.OffsetFlagType, price float64, volume int) string {
f := ctp.CThostFtdcInputOrderField{}
copy(f.BrokerID[:], t.BrokerID)
if info, ok := t.Instruments.Load(instrument); ok {
copy(f.ExchangeID[:], info.(*goctp.InstrumentField).ExchangeID)
}
copy(f.UserID[:], t.InvestorID)
copy(f.InvestorID[:], t.InvestorID)
copy(f.AccountID[:], t.InvestorID)
f.IsAutoSuspend = ctp.TThostFtdcBoolType(0)
f.IsSwapOrder = ctp.TThostFtdcBoolType(0)
f.ForceCloseReason = ctp.THOST_FTDC_FCC_NotForceClose
// 参数赋值
copy(f.OrderRef[:], ordersn)
copy(f.InstrumentID[:], instrument)
f.RequestID = ctp.TThostFtdcRequestIDType(requestid)
f.Direction = ctp.TThostFtdcDirectionType(buySell)
f.CombOffsetFlag[0] = byte(openClose)
f.CombHedgeFlag[0] = byte(goctp.HedgeFlagSpeculation)
// 不同类型的Order
f.OrderPriceType = ctp.THOST_FTDC_OPT_LimitPrice
f.TimeCondition = ctp.THOST_FTDC_TC_IOC
f.VolumeCondition = ctp.THOST_FTDC_VC_AV
f.ContingentCondition = ctp.THOST_FTDC_CC_Immediately
f.LimitPrice = ctp.TThostFtdcPriceType(price)
f.VolumeTotalOriginal = ctp.TThostFtdcVolumeType(volume)
t.t.ReqOrderInsert(f)
return fmt.Sprintf("%d_%s_%d", t.sessionID, goctp.Bytes2String(f.OrderRef[:]), requestid)
}
// ReqOrderAction 撤单
func (t *Trade) ReqOrderAction(orderID string) uintptr {
if o, ok := t.Orders.Load(orderID); ok {
var order = o.(*goctp.OrderField)
f := ctp.CThostFtdcInputOrderActionField{}
copy(f.BrokerID[:], t.BrokerID)
copy(f.UserID[:], t.InvestorID)
copy(f.InstrumentID[:], order.InstrumentID)
copy(f.ExchangeID[:], order.ExchangeID)
copy(f.OrderRef[:], order.OrderRef)
f.ActionFlag = ctp.THOST_FTDC_AF_Delete
f.FrontID = ctp.TThostFtdcFrontIDType(order.FrontID)
f.SessionID = ctp.TThostFtdcSessionIDType(order.SessionID)
t.t.ReqOrderAction(f)
return 0
}
return 0
}
// ReqQryInvestorPosition 查询持仓
func (t *Trade) ReqQueryInvestorPosition() uintptr {
qryPosition := ctp.CThostFtdcQryInvestorPositionField{}
copy(qryPosition.InvestorID[:], t.InvestorID)
copy(qryPosition.BrokerID[:], t.BrokerID)
t.t.ReqQryInvestorPosition(qryPosition)
return 0
}
// ReqQryTradingAccount 查询账户权益
func (t *Trade) ReqQueryTradingAccount() uintptr {
qryAccount := ctp.CThostFtdcQryTradingAccountField{}
copy(qryAccount.InvestorID[:], t.InvestorID)
copy(qryAccount.BrokerID[:], t.BrokerID)
t.t.ReqQryTradingAccount(qryAccount)
return 0
}
// ReqQryInstrument 查询合约信息
func (t *Trade) ReqQueryInstrument() uintptr {
t.t.ReqQryInstrument(ctp.CThostFtdcQryInstrumentField{})
return 0
}
// ********************** 注册客户响应 ************************
// RegOnFrontConnected 注册连接响应
func (t *Trade) RegOnFrontConnected(on goctp.OnFrontConnectedType) {
t.onFrontConnected = on
}
// RegOnFrontConnected 注册连接响应
func (t *Trade) RegOnFrontDisConnected(on goctp.OnFrontDisConnectedType) {
t.onFrontDisConnected = on
}
// RegOnRspUserLogin 注册登陆响应
func (t *Trade) RegOnRspUserLogin(on goctp.OnRspUserLoginType) {
t.onRspUserLogin = on
}
// RegOnRtnOrder 注册委托响应
func (t *Trade) RegOnRtnOrder(on goctp.OnRtnOrderType) {
t.onRtnOrder = on
}
// RegOnErrRtnOrder 注册委托响应
func (t *Trade) RegOnErrRtnOrder(on goctp.OnRtnErrOrderType) {
t.onErrRtnOrder = on
}
// RegOnErrAction 注册撤单响应
func (t *Trade) RegOnErrAction(on goctp.OnRtnErrActionType) {
t.onErrAction = on
}
// RegOnRtnCancel 注册撤单响应
func (t *Trade) RegOnRtnCancel(on goctp.OnRtnOrderType) {
t.onRtnCancel = on
}
// RegOnRtnTrade 注册成交响应
func (t *Trade) RegOnRtnTrade(on goctp.OnRtnTradeType) {
t.onRtnTrade = on
}
// RegOnRtnInstrument 注册合约变化
func (t *Trade) RegOnRtnInstrument(on goctp.OnRtnInstrumentType) {
t.onRtnInstrument = on
}
// RegOnRtnInstrumentStatus 注册合约状态变化
func (t *Trade) RegOnRtnInstrumentStatus(on goctp.OnRtnInstrumentStatusType) {
t.onRtnInstrumentStatus = on
}
// RegOnRtnPosition 注册合约持仓变化
func (t *Trade) RegOnRtnPosition(on goctp.OnRtnPositionType) {
t.onRtnPosition = on
}
// 注册账户权益变化
func (t *Trade) RegOnRtnAccount(on goctp.OnRtnAccountType) {
t.onRtnAccount = on
}
// ********************** 底层接口响应处理 **********************************
// 合约状态响应
func (t *Trade) onStatus(statusField *ctp.CThostFtdcInstrumentStatusField) uintptr {
status, loaded := t.InstrumentStatus.LoadOrStore(goctp.Bytes2String(statusField.InstrumentID[:]), &goctp.InstrumentStatus{
ExchangeID: goctp.Bytes2String(statusField.ExchangeID[:]),
InstrumentID: goctp.Bytes2String(statusField.InstrumentID[:]),
InstrumentStatus: goctp.InstrumentStatusType(statusField.InstrumentStatus),
EnterTime: goctp.Bytes2String(statusField.EnterTime[:]),
})
if loaded {
status.(*goctp.InstrumentStatus).InstrumentStatus = goctp.InstrumentStatusType(statusField.InstrumentStatus)
status.(*goctp.InstrumentStatus).EnterTime = goctp.Bytes2String(statusField.EnterTime[:])
}
if t.onRtnInstrumentStatus != nil {
t.onRtnInstrumentStatus(status.(*goctp.InstrumentStatus))
}
return 0
}
// 成交响应
func (t *Trade) onTrade(tradeField *ctp.CThostFtdcTradeField) uintptr {
key := fmt.Sprintf("%s_%c", tradeField.TradeID, tradeField.Direction)
tf, _ := t.Trades.LoadOrStore(key, &goctp.TradeField{
OrderRef: goctp.Bytes2String(tradeField.OrderRef[:]),
Direction: goctp.DirectionType(tradeField.Direction),
HedgeFlag: goctp.HedgeFlagType(tradeField.HedgeFlag),
InstrumentID: goctp.Bytes2String(tradeField.InstrumentID[:]),
ExchangeID: goctp.Bytes2String(tradeField.ExchangeID[:]),
TradingDay: goctp.Bytes2String(tradeField.TradingDay[:]),
Volume: int(tradeField.Volume),
OffsetFlag: goctp.OffsetFlagType(tradeField.OffsetFlag),
OrderSysID: goctp.Bytes2String(tradeField.OrderSysID[:]),
Price: float64(tradeField.Price),
TradeDate: goctp.Bytes2String(tradeField.TradeDate[:]),
TradeTime: goctp.Bytes2String(tradeField.TradeTime[:]),
TradeID: key,
})
var f = tf.(*goctp.TradeField)
// 处理对应的Order
if ord, ok := t.ordersn4Order.Load(f.OrderRef); ok {
var o = ord.(*goctp.OrderField)
o.LastTradeTime = f.TradeTime
o.VolumeTraded = f.Volume
o.VolumeLeft -= f.Volume
if o.VolumeLeft == 0 {
o.OrderStatus = goctp.OrderStatusAllTraded
o.StatusMsg = "全部成交"
} else {
o.OrderStatus = goctp.OrderStatusPartTradedQueueing
o.StatusMsg = "部分成交"
}
if t.onRtnOrder != nil {
t.onRtnOrder(o)
}
}
// 客户端响应
if t.onRtnTrade != nil {
t.onRtnTrade(f)
}
return 0
}
// 委托响应
func (t *Trade) onOrder(orderField *ctp.CThostFtdcOrderField) uintptr {
var orderStatus goctp.OrderStatusType
if (ctp.THOST_FTDC_OST_Unknown == orderField.OrderStatus) || (ctp.THOST_FTDC_OST_NotTouched == orderField.OrderStatus) {
orderStatus = goctp.OrderStatusNoTradeQueueing
} else {
orderStatus = goctp.OrderStatusType(orderField.OrderStatus)
}
key := fmt.Sprintf("%s", orderField.OrderRef)
if of, ok := t.Orders.LoadOrStore(key, &goctp.OrderField{
InstrumentID: goctp.Bytes2String(orderField.InstrumentID[:]),
RequestID: int(orderField.RequestID),
SessionID: int(orderField.SessionID),
FrontID: int(orderField.FrontID),
OrderRef: goctp.Bytes2String(orderField.OrderRef[:]),
Direction: goctp.DirectionType(orderField.Direction),
OffsetFlag: goctp.OffsetFlagType(orderField.CombOffsetFlag[0]),
HedgeFlag: goctp.HedgeFlagType(orderField.CombHedgeFlag[0]),
LimitPrice: float64(orderField.LimitPrice),
VolumeTotalOriginal: int(orderField.VolumeTotalOriginal),
VolumeLeft: int(orderField.VolumeTotalOriginal),
ExchangeID: goctp.Bytes2String(orderField.ExchangeID[:]),
InsertDate: goctp.Bytes2String(orderField.InsertDate[:]),
InsertTime: goctp.Bytes2String(orderField.InsertTime[:]),
OrderStatus: orderStatus,
StatusMsg: t.ConvertByte2String(orderField.StatusMsg[:], "GB18030"),
IsLocal: int(orderField.SessionID) == t.sessionID,
}); !ok { // 新添加
if t.onRtnOrder != nil {
t.onRtnOrder(of.(*goctp.OrderField))
}
} else {
var o = of.(*goctp.OrderField)
o.OrderStatus = orderStatus
o.StatusMsg = t.ConvertByte2String(orderField.StatusMsg[:], "GB18030")
if o.OrderStatus == goctp.OrderStatusCanceled {
o.RequestID = int(orderField.RequestID)
o.CancelTime = goctp.Bytes2String(orderField.CancelTime[:])
// 错单
if strings.Contains(o.StatusMsg, "被拒绝") {
if t.onErrRtnOrder != nil {
t.onErrRtnOrder(o, &goctp.RspInfoField{
ErrorID: -1,
ErrorMsg: o.StatusMsg,
})
}
} else if t.onRtnCancel != nil {
t.onRtnCancel(o)
}
} else {
o.RequestID = int(orderField.RequestID)
o.OrderSysID = goctp.Bytes2String(orderField.OrderSysID[:])
if len(o.OrderSysID) > 0 {
t.ordersn4Order.Store(o.OrderRef, o)
}
}
}
return 0
}
// 委托错误响应
func (t *Trade) onErrOrder(orderField *ctp.CThostFtdcInputOrderField, infoField *ctp.CThostFtdcRspInfoField) uintptr {
key := fmt.Sprintf("%s", orderField.OrderRef)
of, _ := t.Orders.LoadOrStore(key, &goctp.OrderField{
InstrumentID: goctp.Bytes2String(orderField.InstrumentID[:]),
RequestID: int(orderField.RequestID),
SessionID: t.sessionID,
FrontID: 0,
OrderRef: goctp.Bytes2String(orderField.OrderRef[:]),
Direction: goctp.DirectionType(orderField.Direction),
OffsetFlag: goctp.OffsetFlagType(orderField.CombOffsetFlag[0]),
HedgeFlag: goctp.HedgeFlagType(orderField.CombHedgeFlag[0]),
LimitPrice: float64(orderField.LimitPrice),
VolumeTotalOriginal: int(orderField.VolumeTotalOriginal),
VolumeLeft: int(orderField.VolumeTotalOriginal),
ExchangeID: goctp.Bytes2String(orderField.ExchangeID[:]),
IsLocal: true,
})
var o = of.(*goctp.OrderField)
o.OrderStatus = goctp.OrderStatusCanceled
if t.onErrRtnOrder != nil {
t.onErrRtnOrder(o, &goctp.RspInfoField{ErrorID: int(infoField.ErrorID), ErrorMsg: goctp.Bytes2String(infoField.ErrorMsg[:])})
}
return 0
}
// 撤单错误
func (t *Trade) onErrRtnOrderAction(field *ctp.CThostFtdcOrderActionField, infoField *ctp.CThostFtdcRspInfoField) uintptr {
if t.onErrAction != nil {
t.onErrAction(goctp.Bytes2String(field.OrderRef[:]), &goctp.RspInfoField{
ErrorID: int(infoField.ErrorID),
ErrorMsg: goctp.Bytes2String(infoField.ErrorMsg[:]),
})
}
return 0
}
// 持仓查询响应
func (t *Trade) onPosition(positionField *ctp.CThostFtdcInvestorPositionField, infoField *ctp.CThostFtdcRspInfoField, i int, b bool) uintptr {
if strings.Compare(goctp.Bytes2String(positionField.InstrumentID[:]), "") != 0 {
key := fmt.Sprintf("%s_%c_%c_%c", goctp.Bytes2String(positionField.InstrumentID[:]), goctp.PosiDirectionType(positionField.PosiDirection), goctp.HedgeFlagType(positionField.HedgeFlag), goctp.PositionDateType(positionField.PositionDate))
pf, _ := t.Positions.LoadOrStore(key, &goctp.PositionField{
InstrumentID: goctp.Bytes2String(positionField.InstrumentID[:]),
PositionDirection: goctp.PosiDirectionType(positionField.PosiDirection),
HedgeFlag: goctp.HedgeFlagType(positionField.HedgeFlag),
PositionDate: goctp.PositionDateType(positionField.PositionDate),
ExchangeID: goctp.Bytes2String(positionField.ExchangeID[:]),
})
var p = pf.(*goctp.PositionField)
p.YdPosition = int(positionField.YdPosition)
p.Position = int(positionField.Position)
p.LongFrozen = int(positionField.LongFrozen)
p.ShortFrozen = int(positionField.ShortFrozen)
p.LongFrozenAmount = float64(positionField.LongFrozenAmount)
p.ShortFrozenAmount = float64(positionField.ShortFrozenAmount)
p.OpenVolume = int(positionField.OpenVolume)
p.CloseVolume = int(positionField.CloseVolume)
p.OpenAmount = float64(positionField.OpenAmount)
p.CloseAmount = float64(positionField.CloseAmount)
p.PositionCost = float64(positionField.PositionCost)
p.PreMargin = float64(positionField.PreMargin)
p.UseMargin = float64(positionField.UseMargin)
p.FrozenMargin = float64(positionField.FrozenMargin)
p.FrozenCash = float64(positionField.FrozenCash)
p.FrozenCommission = float64(positionField.FrozenCommission)
p.CashIn = float64(positionField.CashIn)
p.Commission = float64(positionField.Commission)
p.CloseProfit = float64(positionField.CloseProfit)
p.PositionProfit = float64(positionField.PositionProfit)
p.PreSettlementPrice = float64(positionField.PreSettlementPrice)
p.SettlementPrice = float64(positionField.SettlementPrice)
p.OpenCost = float64(positionField.OpenCost)
p.ExchangeMargin = float64(positionField.ExchangeMargin)
p.CombPosition = int(positionField.CombPosition)
p.CombLongFrozen = int(positionField.CombLongFrozen)
p.CombShortFrozen = int(positionField.CombShortFrozen)
p.CloseProfitByDate = float64(positionField.CloseProfitByDate)
p.CloseProfitByTrade = float64(positionField.CloseProfitByTrade)
p.TodayPosition = int(positionField.TodayPosition)
p.StrikeFrozen = int(positionField.StrikeFrozen)
p.StrikeFrozenAmount = float64(positionField.StrikeFrozenAmount)
p.AbandonFrozen = int(positionField.AbandonFrozen)
p.YdStrikeFrozen = int(positionField.YdStrikeFrozen)
p.PositionCostOffset = float64(positionField.PositionCostOffset)
if t.onRtnPosition != nil {
t.onRtnPosition(pf.(*goctp.PositionField))
}
}
return 0
}
// 账户资金响应
func (t *Trade) onAccount(accountField *ctp.CThostFtdcTradingAccountField, infoField *ctp.CThostFtdcRspInfoField, i int, b bool) uintptr {
t.Account.PreMortgage = float64(accountField.PreMortgage)
t.Account.PreDeposit = float64(accountField.PreDeposit)
t.Account.PreBalance = float64(accountField.PreBalance)
t.Account.PreMargin = float64(accountField.PreMargin)
t.Account.InterestBase = float64(accountField.InterestBase)
t.Account.Interest = float64(accountField.Interest)
t.Account.Deposit = float64(accountField.Deposit)
t.Account.Withdraw = float64(accountField.Withdraw)
t.Account.FrozenMargin = float64(accountField.FrozenMargin)
t.Account.FrozenCash = float64(accountField.FrozenCash)
t.Account.FrozenCommission = float64(accountField.FrozenCommission)
t.Account.CurrMargin = float64(accountField.CurrMargin)
t.Account.CashIn = float64(accountField.CashIn)
t.Account.Commission = float64(accountField.Commission)
t.Account.CloseProfit = float64(accountField.CloseProfit)
t.Account.PositionProfit = float64(accountField.PositionProfit)
t.Account.Balance = float64(accountField.Balance)
t.Account.Available = float64(accountField.Available)
t.Account.WithdrawQuota = float64(accountField.WithdrawQuota)
t.Account.Reserve = float64(accountField.Reserve)
t.Account.Credit = float64(accountField.Credit)
t.Account.Mortgage = float64(accountField.Mortgage)
t.Account.ExchangeMargin = float64(accountField.ExchangeMargin)
t.Account.DeliveryMargin = float64(accountField.DeliveryMargin)
t.Account.ExchangeDeliveryMargin = float64(accountField.ExchangeDeliveryMargin)
t.Account.ReserveBalance = float64(accountField.ReserveBalance)
t.Account.CurrencyID = goctp.Bytes2String(accountField.CurrencyID[:])
t.Account.PreFundMortgageIn = float64(accountField.PreFundMortgageIn)
t.Account.PreFundMortgageOut = float64(accountField.PreFundMortgageOut)
t.Account.FundMortgageIn = float64(accountField.FundMortgageIn)
t.Account.FundMortgageOut = float64(accountField.FundMortgageOut)
t.Account.FundMortgageAvailable = float64(accountField.FundMortgageAvailable)
t.Account.MortgageableFund = float64(accountField.MortgageableFund)
if t.onRtnAccount != nil {
t.onRtnAccount(t.Account)
}
return 0
}
// 合约查询响应
func (t *Trade) onInstrument(instrumentField *ctp.CThostFtdcInstrumentField, infoField *ctp.CThostFtdcRspInfoField, i int, b bool) uintptr {
if instrumentField != nil {
instrument := goctp.InstrumentField{
InstrumentID: goctp.Bytes2String(instrumentField.InstrumentID[:]),
ExchangeID: goctp.Bytes2String(instrumentField.ExchangeID[:]),
ProductID: goctp.Bytes2String(instrumentField.ProductID[:]),
ProductClass: goctp.ProductClassType(instrumentField.ProductClass),
MaxMarketOrderVolume: int(instrumentField.MaxMarketOrderVolume),
MinMarketOrderVolume: int(instrumentField.MinMarketOrderVolume),
MaxLimitOrderVolume: int(instrumentField.MaxLimitOrderVolume),
MinLimitOrderVolume: int(instrumentField.MinLimitOrderVolume),
VolumeMultiple: int(instrumentField.VolumeMultiple),
PriceTick: float64(instrumentField.PriceTick),
PositionType: goctp.PositionTypeType(instrumentField.PositionType),
UseMaxMarginSideAlgorithm: instrumentField.MaxMarginSideAlgorithm == '1',
UnderlyingInstrID: goctp.Bytes2String(instrumentField.UnderlyingInstrID[:]),
StrikePrice: float64(instrumentField.StrikePrice),
OptionsType: goctp.OptionsTypeType(instrumentField.OptionsType),
UnderlyingMultiple: float64(instrumentField.UnderlyingMultiple),
CombinationType: goctp.CombinationTypeType(instrumentField.CombinationType),
}
t.Instruments.Store(goctp.Bytes2String(instrumentField.InstrumentID[:]), &instrument)
if t.onRtnInstrument != nil {
t.onRtnInstrument(&instrument)
}
}
return 0
}
// 循环查询持仓&资金
func (t *Trade) qry() {
t.qryTicker = time.NewTicker(1100 * time.Millisecond)
// 等待之前的Order响应完再发送登录通知
ordCnt := t.cntOrder
for range t.qryTicker.C {
if ordCnt == t.cntOrder {
break
}
ordCnt = t.cntOrder
}
qryAccount := ctp.CThostFtdcQryTradingAccountField{}
copy(qryAccount.InvestorID[:], t.InvestorID)
copy(qryAccount.BrokerID[:], t.BrokerID)
qryPosition := ctp.CThostFtdcQryInvestorPositionField{}
copy(qryPosition.InvestorID[:], t.InvestorID)
copy(qryPosition.BrokerID[:], t.BrokerID)
// 启动查询
bQryAccount := false
for range t.qryTicker.C {
if bQryAccount {
t.t.ReqQryTradingAccount(qryAccount)
} else {
t.t.ReqQryInvestorPosition(qryPosition)
}
bQryAccount = !bQryAccount
if !t.IsLogin && !bQryAccount {
// 登录成功响应
t.IsLogin = true
}
}
}
// 确认结算相应
func (t *Trade) onSettlement(confirmField *ctp.CThostFtdcSettlementInfoConfirmField, infoField *ctp.CThostFtdcRspInfoField, i int, b bool) uintptr {
// 查询合约
t.ReqQueryInstrument()
return 0
}
// 登陆响应
func (t *Trade) onLogin(loginField *ctp.CThostFtdcRspUserLoginField, infoField *ctp.CThostFtdcRspInfoField, i int, b bool) uintptr {
if infoField.ErrorID == 0 {
t.sessionID = int(loginField.SessionID)
t.TradingDay = goctp.Bytes2String(loginField.TradingDay[:])
f := ctp.CThostFtdcSettlementInfoConfirmField{}
copy(f.InvestorID[:], t.InvestorID)
copy(f.AccountID[:], t.InvestorID)
copy(f.BrokerID[:], t.BrokerID)
t.t.ReqSettlementInfoConfirm(f)
// 循环查询持仓与权益
go t.qry()
if t.onRspUserLogin != nil {
go func(field *goctp.RspUserLoginField) {
t.onRspUserLogin(field, &goctp.RspInfoField{ErrorID: 0, ErrorMsg: "成功"})
}(&goctp.RspUserLoginField{
TradingDay: t.TradingDay,
LoginTime: goctp.Bytes2String(loginField.LoginTime[:]),
BrokerID: t.BrokerID,
UserID: t.InvestorID,
FrontID: int(loginField.FrontID),
SessionID: t.sessionID,
MaxOrderRef: goctp.Bytes2String(loginField.MaxOrderRef[:]),
})
}
} else {
t.onRspUserLogin(&goctp.RspUserLoginField{}, &goctp.RspInfoField{ErrorID: int(infoField.ErrorID), ErrorMsg: goctp.Bytes2String(infoField.ErrorMsg[:])})
}
return 0
}
// 看穿式验证响应
func (t *Trade) onAuth(auth *ctp.CThostFtdcRspAuthenticateField, info *ctp.CThostFtdcRspInfoField, i int, b bool) uintptr {
if info.ErrorID == 0 {
f := ctp.CThostFtdcReqUserLoginField{}
copy(f.UserID[:], t.InvestorID)
copy(f.BrokerID[:], t.BrokerID)
copy(f.Password[:], t.passWord)
copy(f.UserProductInfo[:], "@HF")
t.t.ReqUserLogin(f)
} else if t.onRspUserLogin != nil {
t.onRspUserLogin(&goctp.RspUserLoginField{}, &goctp.RspInfoField{ErrorID: int(info.ErrorID), ErrorMsg: goctp.Bytes2String(info.ErrorMsg[:])})
}
return 0
}
// 连接前置响应
func (t *Trade) onConnected() uintptr {
if t.onFrontConnected != nil {
t.onFrontConnected()
}
return 0
}
// 连接前置响应
func (t *Trade) onDisConnected(reason int) uintptr {
if nil != t.qryTicker {
t.qryTicker.Stop()
}
if t.onFrontDisConnected != nil {
t.onFrontDisConnected(reason)
}
return 0
}
// 转换中文
func (t *Trade) ConvertByte2String(byte []byte, charset string) string {
var str string
switch charset {
case "GB18030":
var decodeBytes, _ = simplifiedchinese.GB18030.NewDecoder().Bytes(byte)
str = string(decodeBytes)
case "GBK":
var decodeBytes, _ = simplifiedchinese.GBK.NewDecoder().Bytes(byte)
str = string(decodeBytes)
default:
str = string(byte)
}
return str
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/trackertrader/goctp.git
git@gitee.com:trackertrader/goctp.git
trackertrader
goctp
goctp
v1.16.9

搜索帮助

344bd9b3 5694891 D2dac590 5694891