gitee.com/quant1x/engine@v1.8.4/trader/fee.go (about) 1 package trader 2 3 import ( 4 "fmt" 5 "gitee.com/quant1x/engine/config" 6 "gitee.com/quant1x/num" 7 "math" 8 ) 9 10 const ( 11 InvalidFee = float64(0) // 无效的费用 12 InvalidVolume = int(0) // 无效的股数 13 UnknownVolume = int(1) // 未知的股数 14 ) 15 16 // 价格笼子 17 // 18 // 价格笼子是买卖股票申报价格限制的一种制度 19 // 对于主板, 本次新增2%有效申报价格范围要求, 同时增加10个申报价格最小变动单位的安排 20 // A股最小交易变动单位是0.01元,10个也就是0.1元 21 // 买入价取两者高值,卖出价取两者低值. 22 const ( 23 validDeclarationPriceRange = float64(0.02) // 价格限制比例 24 minimumPriceFluctuationUnit = float64(0.10) // 价格浮动最大值 25 ) 26 27 // CalculatePriceCage 计算价格笼子 28 func CalculatePriceCage(strategyParameter config.StrategyParameter, direction Direction, price float64) float64 { 29 priceLimit := 0.000 30 var priceCage, minimumPriceFluctuation float64 31 if direction == BUY { 32 priceCage = price * (1 + strategyParameter.PriceCageRatio) 33 minimumPriceFluctuation = price + strategyParameter.MinimumPriceFluctuationUnit 34 priceLimit = max(priceCage, minimumPriceFluctuation) 35 } else { 36 priceCage = price * (1 - strategyParameter.PriceCageRatio) 37 minimumPriceFluctuation = price - strategyParameter.MinimumPriceFluctuationUnit 38 priceLimit = min(priceCage, minimumPriceFluctuation) 39 } 40 return priceLimit 41 } 42 43 // calculate_price_limit_for_buy 计算合适的买入价格 44 // 45 // 价格笼子, +2%和+0.10哪个大 46 // 目前使用, 当前价格+0.05 47 func calculate_price_limit_for_buy(last_price, price_cage_ratio, minimum_price_fluctuation_unit float64) float64 { 48 // 价格笼子, +2%和+0.10哪个大 49 priceLimit := max(last_price*(1+price_cage_ratio), last_price+minimum_price_fluctuation_unit) 50 // 当前价格+0.05 51 priceLimit = last_price + 0.05 52 // 最后修订价格 53 priceLimit = num.Decimal(priceLimit) 54 return priceLimit 55 } 56 57 // CalculateBuyPriceLimit 计算合适的买入价格 58 // 59 // 价格笼子, +2%和+0.10哪个大 60 // 目前使用, 当前价格+0.05 61 // 62 // Deprecated: 推荐使用 CalculatePriceCage [wangfeng on 2024/3/15 08:35] 63 func CalculateBuyPriceLimit(price float64) float64 { 64 priceLimit := calculate_price_limit_for_buy(price, validDeclarationPriceRange, minimumPriceFluctuationUnit) 65 return priceLimit 66 } 67 68 // calculate_price_limit_for_sell 计算合适的卖出价格 69 // 70 // 价格笼子, -2%和-0.10哪个大 71 // 目前使用, 当前价格-0.01 72 func calculate_price_limit_for_sell(last_price, price_cage_ratio, minimum_price_fluctuation_unit float64) float64 { 73 // 价格笼子, -2%和-0.10哪个小 74 priceLimit := min(last_price*(1-price_cage_ratio), last_price-minimum_price_fluctuation_unit) 75 // 当前价格-0.01 76 priceLimit = last_price - 0.01 77 // 最后修订价格 78 priceLimit = num.Decimal(priceLimit) 79 return priceLimit 80 } 81 82 // CalculateSellPriceLimit 计算卖出价格笼子 83 // 84 // Deprecated: 推荐使用 CalculatePriceCage [wangfeng on 2024/3/15 08:35] 85 func CalculateSellPriceLimit(price float64) float64 { 86 priceLimit := calculate_price_limit_for_sell(price, validDeclarationPriceRange, minimumPriceFluctuationUnit) 87 return priceLimit 88 } 89 90 // 计算买入总费用 91 // 92 // @param direction 交易方向 93 // @param price 价格 94 // @param volume 数量 95 // @param align 费用是否对齐, 即四舍五入. direction=SELL的时候, align必须是true 96 func calculate_transaction_fee(direction Direction, price float64, volume int, align bool) (TotalFee, StampDutyFee, TransferFee, CommissionFee, MarketValue float64) { 97 if volume < 1 { 98 return InvalidFee, 0, 0, 0, 0 99 } 100 vol := float64(volume) 101 amount := vol * price 102 // 1. 印花税, 按照成交金额计算, 买入没有, 卖出, 0.1% 103 _stamp_duty_fee := amount 104 if direction == BUY { 105 _stamp_duty_fee *= traderParameter.StampDutyRateForBuy 106 } else if direction == SELL { 107 _stamp_duty_fee *= traderParameter.StampDutyRateForSell 108 } else { 109 return InvalidFee, 0, 0, 0, 0 110 } 111 if align { 112 _stamp_duty_fee = num.Decimal(_stamp_duty_fee) 113 } 114 // 2. 过户费, 按照股票数量, 双向, 0.06% 115 _transfer_fee := vol * traderParameter.TransferRate 116 if align { 117 _transfer_fee = num.Decimal(_transfer_fee) 118 } 119 // 3. 券商佣金, 按照成交金额计算, 双向, 0.025% 120 _commission_fee := amount * traderParameter.CommissionRate 121 if align { 122 _commission_fee = num.Decimal(_commission_fee) 123 } 124 if align && _commission_fee < traderParameter.CommissionMin { 125 _commission_fee = traderParameter.CommissionMin 126 } 127 // 4. 股票市值 128 _marketValue := amount 129 if align { 130 _marketValue = num.Decimal(_marketValue) 131 } 132 // 5. 计算费用 133 _fee := _stamp_duty_fee + _transfer_fee + _commission_fee 134 // 6. 计算总费用 135 _total_fee := _fee 136 if direction == BUY { 137 // 买入操作, 加上股票市值 138 _total_fee += _marketValue 139 } else { 140 // 卖出操作, 股票市值减去费用 141 _marketValue -= _fee 142 } 143 return _total_fee, _stamp_duty_fee, _transfer_fee, _commission_fee, _marketValue 144 } 145 146 // EvaluateFeeForBuy 评估买入总费用 147 func EvaluateFeeForBuy(securityCode string, fund, price float64) *TradeFee { 148 f := TradeFee{ 149 SecurityCode: securityCode, 150 Price: price, 151 Volume: UnknownVolume, 152 Direction: BUY, 153 } 154 f.Volume = f.CalculateNumToBuy(fund, price) 155 return &f 156 } 157 158 // EvaluateFeeForSell 评估卖出费用 159 func EvaluateFeeForSell(securityCode string, price float64, volume int) *TradeFee { 160 f := TradeFee{ 161 SecurityCode: securityCode, 162 Price: price, 163 Volume: volume, 164 Direction: SELL, 165 } 166 f.TotalFee, f.StampDutyFee, f.TransferFee, f.CommissionFee, f.MarketValue = calculate_transaction_fee(f.Direction, f.Price, f.Volume, true) 167 return &f 168 } 169 170 // EvaluatePriceForSell 评估卖出价格 171 // 172 // 固定收益率>0, 重新评估卖出价格, 以确保卖出后的净利润不低于固定收益率 173 func EvaluatePriceForSell(securityCode string, price float64, volume int, fixedYield float64) *TradeFee { 174 f := TradeFee{ 175 SecurityCode: securityCode, 176 Price: price, 177 Volume: volume, 178 Direction: SELL, 179 } 180 f.TotalFee, f.StampDutyFee, f.TransferFee, f.CommissionFee, f.MarketValue = calculate_transaction_fee(f.Direction, f.Price, f.Volume, true) 181 if fixedYield > 0 { 182 fee := (f.TotalFee-f.TransferFee)*(1+fixedYield) + f.TransferFee 183 amount := float64(volume) * price 184 marketValue := amount * (1 + fixedYield) 185 totalFee := fee + marketValue 186 fixedPrice := totalFee / float64(volume) 187 f.Price = num.Decimal(fixedPrice) 188 f.TotalFee, f.StampDutyFee, f.TransferFee, f.CommissionFee, f.MarketValue = calculate_transaction_fee(f.Direction, f.Price, f.Volume, true) 189 } 190 return &f 191 } 192 193 // TradeFee 交易费用 194 type TradeFee struct { 195 Direction Direction // 交易方向 196 SecurityCode string // 证券代码 197 Price float64 // 价格 198 Volume int // 数量 199 StampDutyFee float64 // 印花税, 按照成交金额计算, 双向, 默认单向, 费率0.1% 200 TransferFee float64 // 过户费, 按照股票数量, 双向, 默认是0.06% 201 CommissionFee float64 // 券商佣金, 按照成交金额计算, 双向, 0.025% 202 MarketValue float64 // 股票市值 203 TotalFee float64 // 支出总费用 204 } 205 206 func (f *TradeFee) log() { 207 fmt.Printf("trader[%s]: code=%s, 综合费用=%.02f, 委托价格=%.02f, 数量=%d, 其中印花说=%.02f, 过户费=%.02f, 佣金=%.02f, 股票=%.02f", f.Direction, f.SecurityCode, f.TotalFee, f.Price, 208 f.Volume, f.StampDutyFee, f.TransferFee, f.CommissionFee, f.MarketValue) 209 } 210 211 // CalculateNumToBuy 估算可买股票数量 212 // 213 // 评估买入操作涉及的所有费用 214 // 返回100股的整数倍 215 func (f *TradeFee) CalculateNumToBuy(fund, price float64) int { 216 f.Direction = BUY 217 f.Price = price 218 // 1. 计算每股费用 219 _fee, _, _, _, _ := calculate_transaction_fee(f.Direction, f.Price, UnknownVolume, false) 220 if _fee == InvalidFee { 221 return InvalidVolume 222 } 223 // 2. 计算股数 224 _vol := fund / _fee 225 // 3. 换算成手数 226 _vol = math.Floor(_vol / 100) 227 // 4. 转成整数 228 f.Volume = int(_vol) * 100 229 // 5. 重新计算 230 f.TotalFee, f.StampDutyFee, f.TransferFee, f.CommissionFee, f.MarketValue = calculate_transaction_fee(f.Direction, f.Price, f.Volume, true) 231 if f.TotalFee == InvalidFee { 232 return InvalidVolume 233 } else if _fee > fund { 234 // 如果费用超了, 则减去1手(100股) 235 f.Volume -= 100 236 // 重新计算交易费用 237 f.TotalFee, f.StampDutyFee, f.TransferFee, f.CommissionFee, f.MarketValue = calculate_transaction_fee(f.Direction, f.Price, f.Volume, true) 238 } 239 return f.Volume 240 } 241 242 // CalculateFundFromSell 计算卖出股票后净收益 243 func (f *TradeFee) CalculateFundFromSell(price float64, volume int) float64 { 244 f.Direction = SELL 245 f.Price = price 246 f.Volume = volume 247 f.TotalFee, f.StampDutyFee, f.TransferFee, f.CommissionFee, f.MarketValue = calculate_transaction_fee(f.Direction, f.Price, f.Volume, true) 248 if f.TotalFee == InvalidFee { 249 return InvalidFee 250 } 251 return f.MarketValue 252 }