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 }