gitee.com/quant1x/engine@v1.8.4/trader/trader.go (about) 1 package trader 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "gitee.com/quant1x/engine/cache" 7 "gitee.com/quant1x/engine/config" 8 "gitee.com/quant1x/engine/models" 9 "gitee.com/quant1x/exchange" 10 "gitee.com/quant1x/gox/http" 11 "gitee.com/quant1x/gox/logger" 12 urlpkg "net/url" 13 "path/filepath" 14 "strings" 15 ) 16 17 var ( 18 traderParameter = config.TraderConfig() 19 // miniQMT代理服务器地址 20 //urlPrefixMiniQmtProxy = "http://10.211.55.3:18168/qmt" 21 urlPrefixMiniQmtProxy = traderParameter.ProxyUrl 22 // 查询前缀 23 urlPrefixForQuery = urlPrefixMiniQmtProxy + "/query" 24 // 交易前缀 25 urlPrefixForTrade = urlPrefixMiniQmtProxy + "/trade" 26 // 查询账户信息 27 urlAccount = urlPrefixForQuery + "/asset" 28 // 查询持仓信息 29 urlHolding = urlPrefixForQuery + "/holding" 30 // 查询委托 31 urlOrders = urlPrefixForQuery + "/order" 32 // 委托 33 urlPlaceOrder = urlPrefixForTrade + "/order" 34 // 撤单 35 urlCancelOrder = urlPrefixForTrade + "/cancel" 36 // qmt账户数据路径: qmt/账户id 37 traderQmtOrderPath = filepath.Join(cache.GetQmtCachePath(), traderParameter.AccountId) 38 ) 39 40 // Direction 交易方向 41 type Direction string 42 43 func (d Direction) String() string { 44 return string(d) 45 } 46 47 // 交易类型标志 48 func (d Direction) Flag() string { 49 flag := d.String() 50 return flag[0:1] 51 } 52 53 const ( 54 BUY Direction = "buy" // 买入 55 SELL Direction = "sell" // 卖出 56 JUNK Direction = "junk" // 废单 57 ) 58 59 type ProxyResult struct { 60 Status int `json:"status"` 61 Message string `json:"message"` 62 } 63 64 // OrderResult 结果 65 type OrderResult struct { 66 ProxyResult 67 OrderId int `json:"order_id"` 68 } 69 70 // AccountDetail 账户信息 71 type AccountDetail struct { 72 TotalAsset float64 `name:"总金额" json:"total_asset"` 73 Cash float64 `name:"可用" json:"cash"` 74 MarketValue float64 `name:"市值" json:"market_value"` 75 FrozenCash float64 `name:"冻结" json:"frozen_cash"` 76 } 77 78 // PositionDetail 持仓信息 79 type PositionDetail struct { 80 AccountType int `name:"账户类型" json:"account_type"` // 账户类型 81 AccountId string `name:"资金账户" json:"account_id"` // 资金账号 82 StockCode string `name:"证券代码" json:"stock_code"` // 证券代码, 例如"600000.SH" 83 Volume int `name:"持仓数量" json:"volume"` // 持仓数量,股票以'股'为单位, 债券以'张'为单位 84 CanUseVolume int `name:"可卖数量" json:"can_use_volume"` // 可用数量, 股票以'股'为单位, 债券以'张'为单位 85 OpenPrice float64 `name:"开仓价" json:"open_price"` // 开仓价 86 MarketValue float64 `name:"市值" json:"market_value"` // 市值 87 FrozenVolume int `name:"冻结数量" json:"frozen_volume"` // 冻结数量 88 OnRoadVolume int `name:"在途股份" json:"on_road_volume"` // 在途股份 89 YesterdayVolume int `name:"昨夜拥股" json:"yesterday_volume"` // 昨夜拥股 90 AvgPrice float64 `name:"成本价" json:"avg_price"` // 成本价 91 } 92 93 // OrderDetail 委托订单 94 type OrderDetail struct { 95 AccountType int `name:"账户类型" json:"account_type"` // 账户类型 96 AccountId string `name:"资金账户" json:"account_id"` // 资金账号 97 OrderTime string `name:"委托时间" json:"order_time"` // 报单时间 98 StockCode string `name:"证券代码" json:"stock_code"` // 证券代码, 例如"600000.SH" 99 OrderType int `name:"订单类型" json:"order_type"` // 委托类型, 23:买, 24:卖 100 Price float64 `name:"委托价格" json:"price"` // 报价价格, 如果price_type为指定价, 那price为指定的价格, 否则填0 101 PriceType int `name:"报价类型" json:"price_type"` // 报价类型, 详见帮助手册 102 OrderVolume int `name:"委托量" json:"order_volume"` // 委托数量, 股票以'股'为单位, 债券以'张'为单位 103 OrderId int `name:"订单ID" json:"order_id"` // 委托编号 104 OrderSysid string `name:"合同编号" json:"order_sysid"` // 柜台编号 105 TradedPrice float64 `name:"成交均价" json:"traded_price"` // 成交均价 106 TradedVolume int `name:"成交数量" json:"traded_volume"` // 成交数量, 股票以'股'为单位, 债券以'张'为单位 107 OrderStatus int `name:"订单状态" json:"order_status"` // 委托状态 108 StatusMessage string `name:"委托状态描述" json:"status_msg"` // 委托状态描述, 如废单原因 109 StrategyName string `name:"策略名称" json:"strategy_name"` // 策略名称 110 OrderRemark string `name:"委托备注" json:"order_remark"` // 委托备注 111 } 112 113 // SecurityCode 获取证券代码 114 func (d OrderDetail) SecurityCode() string { 115 return exchange.CorrectSecurityCode(d.StockCode) 116 } 117 118 // QueryAccount 查询账户信息 119 func QueryAccount() (*AccountDetail, error) { 120 data, err := http.Post(urlAccount, "") 121 if err != nil { 122 logger.Errorf("trader: 查询账户异常: %+v", err) 123 return nil, err 124 } 125 var detail AccountDetail 126 err = json.Unmarshal(data, &detail) 127 if err != nil { 128 logger.Errorf("trader: 解析json异常: %+v", err) 129 return nil, err 130 } 131 return &detail, nil 132 } 133 134 // QueryHolding 查询持仓 135 func QueryHolding() ([]PositionDetail, error) { 136 data, err := http.Post(urlHolding, "") 137 if err != nil { 138 logger.Errorf("trader: 查询持仓异常: %+v", err) 139 return nil, err 140 } 141 var detail []PositionDetail 142 err = json.Unmarshal(data, &detail) 143 if err != nil { 144 logger.Errorf("trader: 解析json异常: %+v", err) 145 return nil, err 146 } 147 return detail, nil 148 } 149 150 // QueryOrders 查询当日委托 151 func QueryOrders() ([]OrderDetail, error) { 152 data, err := http.Post(urlOrders, "") 153 if err != nil { 154 logger.Errorf("trader: 查询委托异常: %+v", err) 155 return nil, err 156 } 157 var detail []OrderDetail 158 err = json.Unmarshal(data, &detail) 159 if err != nil { 160 logger.Errorf("trader: 解析json异常: %+v", err) 161 return nil, err 162 } 163 return detail, nil 164 } 165 166 // CancelOrder 撤单 167 func CancelOrder(orderId int) error { 168 params := urlpkg.Values{ 169 "order_id": {fmt.Sprintf("%d", orderId)}, 170 } 171 body := params.Encode() 172 logger.Infof("trader-cancel: %s", body) 173 data, err := http.Post(urlCancelOrder, body) 174 if err != nil { 175 logger.Errorf("trader-cancel: 撤单操作异常: %+v", err) 176 return err 177 } 178 var detail OrderResult 179 err = json.Unmarshal(data, &detail) 180 if err != nil { 181 logger.Errorf("trader-cancel: 解析json异常: %+v", err) 182 return err 183 } 184 logger.Infof("trader-cancel: %s, response: status=%d", body, detail.Status) 185 return nil 186 } 187 188 // PlaceOrder 下委托订单 189 func PlaceOrder(direction Direction, model models.Strategy, securityCode string, priceType PriceType, price float64, volume int) (int, error) { 190 strategyName := models.QmtStrategyName(model) 191 orderRemark := models.QmtOrderRemark(model) 192 return DirectOrder(direction, strategyName, orderRemark, securityCode, priceType, price, volume) 193 } 194 195 // 直接下单(透传) 196 func DirectOrder(direction Direction, strategyName, orderRemark, securityCode string, priceType PriceType, price float64, volume int) (int, error) { 197 _, mflag, symbol := exchange.DetectMarket(securityCode) 198 params := urlpkg.Values{ 199 "direction": {direction.String()}, 200 "code": {fmt.Sprintf("%s.%s", symbol, strings.ToUpper(mflag))}, 201 "price_type": {fmt.Sprintf("%d", priceType)}, 202 "price": {fmt.Sprintf("%f", price)}, 203 "volume": {fmt.Sprintf("%d", volume)}, 204 "strategy": {strategyName}, 205 "remark": {orderRemark}, 206 } 207 body := params.Encode() 208 logger.Infof("trader-order: %s", body) 209 data, err := http.Post(urlPlaceOrder, body) 210 if err != nil { 211 logger.Errorf("trader-order: 下单操作异常: %+v", err) 212 return -1, err 213 } 214 var detail OrderResult 215 err = json.Unmarshal(data, &detail) 216 if err != nil { 217 logger.Errorf("trader-order: 解析json异常: %+v", err) 218 return -1, err 219 } 220 logger.Infof("trade-order: %s, response: order_id=%d", body, detail.OrderId) 221 return detail.OrderId, nil 222 } 223 224 // 计算策略标的的可用资金 225 func CalculateFundForStrategy(model models.Strategy) float64 { 226 strategyCode := model.Code() 227 rule := config.GetStrategyParameterByCode(strategyCode) 228 if rule == nil { 229 return InvalidFee 230 } 231 fund := CalculateAvailableFund(rule) 232 return fund 233 }