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  }