gitee.com/quant1x/engine@v1.8.4/trader/holdingorders.go (about) 1 package trader 2 3 import ( 4 "gitee.com/quant1x/exchange" 5 "gitee.com/quant1x/gox/api" 6 "gitee.com/quant1x/gox/logger" 7 "slices" 8 "sync" 9 ) 10 11 //// HoldingOrder 持仓订单 12 //type HoldingOrder struct { 13 // AccountType int `name:"账户类型" json:"account_type" dataframe:"account_type"` // 账户类型 14 // Date string `name:"信号日期" json:"date" dataframe:"date"` // 日期 15 // AccountId string `name:"资金账户" json:"account_id" dataframe:"account_id"` // 资金账号 16 // OrderTime string `name:"委托时间" json:"order_time" dataframe:"order_time"` // 报单时间 17 // StockCode string `name:"证券代码" json:"stock_code" dataframe:"stock_code"` // 证券代码, 例如"600000.SH" 18 // OrderType int `name:"订单类型" json:"order_type" dataframe:"order_type"` // 委托类型, 23:买, 24:卖 19 // Price float64 `name:"委托价格" json:"price" dataframe:"price"` // 报价价格, 如果price_type为指定价, 那price为指定的价格, 否则填0 20 // PriceType int `name:"报价类型" json:"price_type" dataframe:"price_type"` // 报价类型, 详见帮助手册 21 // OrderVolume int `name:"委托量" json:"order_volume" dataframe:"order_volume"` // 委托数量, 股票以'股'为单位, 债券以'张'为单位 22 // OrderId int `name:"订单ID" json:"order_id" dataframe:"order_id"` // 委托编号 23 // OrderSysid string `name:"合同编号" json:"order_sysid" dataframe:"order_sysid"` // 柜台编号 24 // TradedPrice float64 `name:"成交均价" json:"traded_price" dataframe:"traded_price"` // 成交均价 25 // TradedVolume int `name:"成交数量" json:"traded_volume" dataframe:"traded_volume"` // 成交数量, 股票以'股'为单位, 债券以'张'为单位 26 // OrderStatus int `name:"订单状态" json:"order_status" dataframe:"order_status"` // 委托状态 27 // StatusMessage string `name:"委托状态描述" json:"status_msg" dataframe:"status_message"` // 委托状态描述, 如废单原因 28 // StrategyName string `name:"策略名称" json:"strategy_name" dataframe:"strategy_name"` // 策略名称 29 // OrderRemark string `name:"委托备注" json:"order_remark" dataframe:"order_remark"` // 委托备注 30 // HoldingPeriod int `name:"持股周期" json:"holding_period" dataframe:"holding_period"` // 持股周期 31 //} 32 // 33 //// Key 索引字段: 日期/订单类型/策略名称/证券代码 34 //func (this HoldingOrder) Key() string { 35 // return fmt.Sprintf("%s/%d/%s/%s", this.Date, this.OrderType, this.StrategyName, this.StockCode) 36 //} 37 38 type HoldingPosition struct { 39 AccountType int `name:"账户类型" dataframe:"account_type"` // 账户类型 40 AccountId string `name:"资金账户" dataframe:"account_id"` // 资金账号 41 StockCode string `name:"证券代码" dataframe:"stock_code"` // 证券代码, 例如"600000.SH" 42 Volume int `name:"持仓数量" dataframe:"volume"` // 持仓数量,股票以'股'为单位, 债券以'张'为单位 43 CanUseVolume int `name:"可卖数量" dataframe:"can_use_volume"` // 可用数量, 股票以'股'为单位, 债券以'张'为单位 44 OpenPrice float64 `name:"开仓价" dataframe:"open_price"` // 开仓价 45 MarketValue float64 `name:"市值" dataframe:"market_value"` // 市值 46 FrozenVolume int `name:"冻结数量" dataframe:"frozen_volume"` // 冻结数量 47 OnRoadVolume int `name:"在途股份" dataframe:"on_road_volume"` // 在途股份 48 YesterdayVolume int `name:"昨夜拥股" dataframe:"yesterday_volume"` // 昨夜拥股 49 AvgPrice float64 `name:"成本价" dataframe:"avg_price"` // 成本价 50 HoldingPeriod int `name:"持股周期" dataframe:"holding_period"` // 持股周期 51 } 52 53 var ( 54 //holdingOnce coroutine.RollingOnce 55 holdingOrders []HoldingPosition 56 holdingMutex sync.RWMutex 57 ) 58 59 // 懒加载持仓个股的持股周期 60 func lazyLoadHoldingOrder() { 61 holdingMutex.Lock() 62 defer holdingMutex.Unlock() 63 methodName := "lazyLoadHoldingOrder" 64 // 1. 获取持仓列表 65 positions, err := QueryHolding() 66 if err != nil { 67 logger.Errorf("查询持仓列表失败, error=%+v", err) 68 return 69 } 70 // 过滤掉清仓的个股 71 positions = api.Filter(positions, func(detail PositionDetail) bool { 72 return detail.Volume > 0 73 }) 74 // 清空缓存 75 clear(holdingOrders) 76 // 2. 用持仓列表遍历历史订单缓存文件, 补全持仓订单 77 dates := GetLocalOrderDates() 78 if len(dates) == 0 { 79 return 80 } 81 // 3. 重新评估持仓范围, 有可能存在日期没有成交的可能 82 firstDate := dates[0] 83 lastTradeDate := exchange.LastTradeDate() 84 dates = exchange.TradingDateRange(firstDate, lastTradeDate) 85 // 反转日期切片 86 slices.Reverse(dates) 87 // 4. 用持仓列表遍历历史订单缓存文件, 补全持仓订单 88 for _, position := range positions { 89 var holding HoldingPosition 90 _ = api.Copy(&holding, &position) 91 code := position.StockCode 92 volume := position.Volume 93 // 矫正证券代码 94 securityCode := exchange.CorrectSecurityCode(position.StockCode) 95 // 历史记录合计买数量 96 tmpTradedVolume := 0 97 // 最早的持股日期 98 earlierDate := lastTradeDate 99 // 持股周期 100 holdingPeriod := 0 101 //if code == "001216.SZ" { 102 // fmt.Println(code) 103 //} 104 // 从当前日期往前回溯订单 105 for _, date := range dates { 106 isLastTradeDate := date == lastTradeDate 107 // 获取date的订单列表 108 orders := GetOrderList(date) 109 if len(orders) == 0 && isLastTradeDate { 110 // 如果本地缓存订单列表为空, 且是最后一个交易日, 则从券商获取订单列表 111 orders, _ = QueryOrders() 112 } 113 if len(orders) == 0 { 114 // 如果订单列表为空, 跳过 115 continue 116 } 117 orders = api.Filter(orders, func(detail OrderDetail) bool { 118 return detail.StockCode == code 119 }) 120 if len(orders) == 0 { 121 continue 122 } 123 currentTradedVolume := 0 124 for _, order := range orders { 125 if order.OrderType != STOCK_BUY && order.OrderType != STOCK_SELL { 126 // 如果不是买入和卖出, 忽略 127 continue 128 } 129 plus := 1 // 默认相加 130 if order.OrderType == STOCK_SELL { 131 // 卖出则减 132 plus = -1 133 } 134 if order.OrderStatus == ORDER_PART_SUCC || order.OrderStatus == ORDER_SUCCEEDED { 135 // 部成和已成 , 成交数量累加 136 currentTradedVolume += plus * order.TradedVolume 137 } 138 } 139 earlierDate = date 140 tmpTradedVolume += currentTradedVolume 141 if tmpTradedVolume == volume { 142 // 如果订单合计成交量等于持仓量, 则退出 143 break 144 } 145 } 146 if tmpTradedVolume != volume { 147 // 历史已成买入量和持仓量不一致, 按照持仓逻辑, 会当成持股最后一天来处理 148 logger.Errorf("[%s]: 加载(%s)持仓记录异常, 历史委托记录合并持仓量不一致", methodName, securityCode) 149 } 150 // 计算持股周期 151 dateRanges := exchange.TradingDateRange(earlierDate, lastTradeDate) 152 holdingPeriod = len(dateRanges) - 1 153 holding.HoldingPeriod = holdingPeriod 154 holdingOrders = append(holdingOrders, holding) 155 } 156 // 5. 对于非策略订单的处理 157 } 158 159 // GetHoldingPeriodList 获取持仓周期列表 160 func GetHoldingPeriodList() []HoldingPosition { 161 lazyLoadHoldingOrder() 162 return holdingOrders 163 }