gitee.com/quant1x/engine@v1.8.4/trader/account.go (about)

     1  package trader
     2  
     3  import (
     4  	"gitee.com/quant1x/engine/config"
     5  	"gitee.com/quant1x/gox/coroutine"
     6  	"gitee.com/quant1x/gox/logger"
     7  	"gitee.com/quant1x/num"
     8  )
     9  
    10  var (
    11  	onceAccount            coroutine.RollingOnce
    12  	accountTheoreticalFund = 0.00
    13  	accountRemainingCash   = 0.00
    14  )
    15  
    16  func lazyInitFundPool() {
    17  	accountTheoreticalFund, accountRemainingCash = calculateTheoreticalFund()
    18  }
    19  
    20  // 计算理论上可用的资金
    21  func calculateTheoreticalFund() (theoretical, cash float64) {
    22  	theoretical = InvalidFee
    23  	cash = InvalidFee
    24  	// 1. 查询 总资产和可用
    25  	// acc_total, acc_cash = self.account_available()
    26  	acc, err := QueryAccount()
    27  	if err != nil {
    28  		return
    29  	}
    30  	// 2. 查询持仓可卖的股票 TODO: 如果确定了可卖出的市值, 怎么保证当日必须卖出?
    31  	// positions = self.query_positions()
    32  	positions, err := QueryHolding()
    33  	if err != nil {
    34  		return
    35  	}
    36  	can_use_amount := 0.00
    37  	// 3. 设置一个可卖股票的市值波动范围, 这里暂定10%
    38  	vix := 0.10
    39  	acc_value := 0.00 // 总市值
    40  	for _, position := range positions {
    41  		acc_value += position.MarketValue
    42  		if position.CanUseVolume < 1 {
    43  			continue
    44  		}
    45  		// 计算现价
    46  		market_price := position.MarketValue / float64(position.Volume)
    47  		// 累计可卖的市值: 可卖数量 * 市价
    48  		can_use_value := market_price * float64(position.CanUseVolume)
    49  		can_use_amount += can_use_value * (1 - vix)
    50  	}
    51  	acc_value = num.Decimal(acc_value)
    52  	can_use_amount = num.Decimal(can_use_amount)
    53  	// 4. 确定可用资金总量: 账户可以资金 + 当日可卖出的总市值 - 预留现金
    54  	can_use_cash := acc.Cash + can_use_amount - traderParameter.KeepCash
    55  	// 5. 计算预留仓位, 给下一个交易日留position_ratio仓位
    56  	reserve_cash := num.Decimal(acc.TotalAsset * traderParameter.PositionRatio)
    57  	// 6. 计算当日可用仓位: 可用资金总量 - 预留资金总量
    58  	available := can_use_cash - reserve_cash
    59  	logger.Warnf("账户资金: 可用=%.02f, 市值=%.02f, 预留=%.02f, 可买=%.02f, 可卖=%.02f", acc.Cash, acc_value, reserve_cash, available, can_use_amount)
    60  	// 7. 如果当日可用金额大于资金账户的可用金额, 输出风险提示
    61  	if available > acc.Cash {
    62  		logger.Warnf("!!! 持仓占比[{}%], 已超过可总仓位的[{}%], 必须在收盘前择机降低仓位, 以免影响下一个交易日的买入操作 !!!", num.Decimal(100*(acc_value/acc.TotalAsset)),
    63  			num.Decimal(100*(1-traderParameter.PositionRatio)))
    64  	}
    65  	// 8. 重新修订可用金额
    66  	available = (acc.TotalAsset - traderParameter.KeepCash) * traderParameter.PositionRatio
    67  	if available > acc.Cash {
    68  		available = acc.Cash
    69  	}
    70  	theoretical = available
    71  	cash = acc.Cash
    72  	return theoretical, cash
    73  }
    74  
    75  // CalculateAvailableFund 计算一只股票的可动用资金量
    76  //
    77  // 参数:
    78  //
    79  //	totalBalance: 总账户余额
    80  //	marketValue: 股票当前市值
    81  //	averageCost: 平均买入成本(用于计算盈亏)
    82  //	commission: 交易佣金率
    83  //
    84  // 返回值:
    85  //
    86  //	availableFund: 可动用资金量
    87  func CalculateAvailableFund(strategyParameter *config.StrategyParameter) float64 {
    88  	onceAccount.Do(lazyInitFundPool)
    89  	if strategyParameter.Total < 1 {
    90  		return InvalidFee
    91  	}
    92  	// 1. 检查可用资金
    93  	if accountTheoreticalFund <= InvalidFee {
    94  		return InvalidFee
    95  	}
    96  	// 2. 计算策略的可用资金, 总可用资金*策略权重
    97  	strategy_fund := accountTheoreticalFund * strategyParameter.Weight
    98  	single_funds_available := num.Decimal(strategy_fund / float64(strategyParameter.Total))
    99  	// 3. 检查策略的可用资金范围
   100  	if single_funds_available > strategyParameter.FeeMax {
   101  		single_funds_available = strategyParameter.FeeMax
   102  	} else if single_funds_available < strategyParameter.FeeMin {
   103  		return InvalidFee
   104  	}
   105  	// 4. 检查可用资金的最大值和最小值
   106  	if single_funds_available > traderParameter.BuyAmountMax {
   107  		single_funds_available = traderParameter.BuyAmountMax
   108  	} else if single_funds_available < traderParameter.BuyAmountMin {
   109  		return InvalidFee
   110  	}
   111  	return single_funds_available
   112  }