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  }