RiskManager.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. import { logger } from '../../utils/logger.js'
  2. /**
  3. * 风险管理器 - 多维度风险评估和基差分析
  4. */
  5. export class RiskManager {
  6. constructor(accountManager) {
  7. this.accountManager = accountManager
  8. this.basisHistory = []
  9. this.basisConfig = {
  10. maxDeviation: 200,
  11. alertThreshold: 100,
  12. historyRetentionHours: 24,
  13. enabledSymbols: ['BTC-USD', 'ETH-USD'],
  14. normalThreshold: 0.5,
  15. warningThreshold: 1.0,
  16. criticalThreshold: 2.0, // 2.0% 基差异常阈值
  17. }
  18. }
  19. async initialize() {
  20. logger.info('RiskManager初始化')
  21. }
  22. async start() {
  23. logger.info('RiskManager启动')
  24. }
  25. async stop() {
  26. logger.info('RiskManager停止')
  27. this.basisHistory = []
  28. }
  29. getStatus() {
  30. return {
  31. name: 'RiskManager',
  32. status: 'running',
  33. lastUpdate: Date.now(),
  34. details: {
  35. basisHistoryLength: this.basisHistory.length,
  36. lastRiskCheck: Date.now(),
  37. },
  38. }
  39. }
  40. /**
  41. * 基差风险评估
  42. */
  43. async assessBasisRisk() {
  44. try {
  45. // 模拟基差数据计算(生产环境应使用真实API)
  46. let spotPrice = null
  47. let futuresPrice = null
  48. try {
  49. spotPrice = 65000 // 现货价格估算
  50. futuresPrice = 65000 * (1 + (Math.random() - 0.5) * 0.002) // 期货价格:±0.1% 随机偏差
  51. logger.debug(`基差评估使用估算价格: 现货=${spotPrice}, 期货=${futuresPrice.toFixed(2)}`)
  52. } catch (error) {
  53. logger.warn('基差风险评估时价格获取失败', { error })
  54. }
  55. if (!spotPrice || !futuresPrice) {
  56. return {
  57. riskLevel: 'LOW',
  58. currentBasis: null,
  59. confidence: 0.3,
  60. message: '无法获取实时价格数据,基差风险评估置信度低',
  61. timestamp: Date.now(),
  62. }
  63. }
  64. // 计算基差和基差率
  65. const basis = futuresPrice - spotPrice
  66. const basisPercent = (basis / spotPrice) * 100
  67. // 基差风险评估逻辑
  68. let riskLevel
  69. let message
  70. const absBasisPercent = Math.abs(basisPercent)
  71. if (absBasisPercent > this.basisConfig.criticalThreshold) {
  72. riskLevel = 'CRITICAL'
  73. message = `基差极端偏离 ${basisPercent.toFixed(3)}%,市场可能存在异常`
  74. } else if (absBasisPercent > this.basisConfig.warningThreshold) {
  75. riskLevel = 'HIGH'
  76. message = `基差偏离较大 ${basisPercent.toFixed(3)}%,套利风险增加`
  77. } else if (absBasisPercent > this.basisConfig.normalThreshold) {
  78. riskLevel = 'MEDIUM'
  79. message = `基差轻微偏离 ${basisPercent.toFixed(3)}%,需持续监控`
  80. } else {
  81. riskLevel = 'LOW'
  82. message = `基差正常 ${basisPercent.toFixed(3)}%,风险可控`
  83. }
  84. // 保存基差历史数据
  85. const basisDataPoint = {
  86. spotPrice,
  87. futuresPrice,
  88. basis,
  89. basisPercent,
  90. timestamp: Date.now(),
  91. }
  92. this.updateBasisHistory(basisDataPoint)
  93. return {
  94. riskLevel,
  95. currentBasis: basisPercent,
  96. confidence: 0.8,
  97. message,
  98. timestamp: Date.now(),
  99. }
  100. } catch (error) {
  101. logger.error('基差风险评估失败', { error: error.message })
  102. return {
  103. riskLevel: 'MEDIUM',
  104. currentBasis: null,
  105. confidence: 0.2,
  106. message: '基差风险评估异常,建议谨慎交易',
  107. timestamp: Date.now(),
  108. }
  109. }
  110. }
  111. /**
  112. * 智能风险评估 - 多维度风险分析
  113. */
  114. async calculateIntelligentRiskScore(stats) {
  115. const factors = []
  116. const recommendations = []
  117. let riskScore = 0
  118. const accountStates = this.accountManager.getAllAccountStates()
  119. // 1. 交易成功率风险 (权重30%)
  120. const successRate = stats.totalTrades > 0 ? stats.successfulTrades / stats.totalTrades : 1
  121. if (successRate < 0.5) {
  122. riskScore += 30
  123. factors.push(`低成功率: ${(successRate * 100).toFixed(1)}%`)
  124. recommendations.push('建议降低交易频率或调整策略参数')
  125. } else if (successRate < 0.7) {
  126. riskScore += 15
  127. factors.push(`中等成功率: ${(successRate * 100).toFixed(1)}%`)
  128. }
  129. // 2. 仓位集中度风险 (权重25%)
  130. const totalPosition = Array.from(accountStates.values()).reduce(
  131. (sum, account) => sum + Math.abs(account.netPosition),
  132. 0,
  133. )
  134. const totalBalance = Array.from(accountStates.values()).reduce((sum, account) => sum + account.lastBalance, 0)
  135. const avgBalance = totalBalance / Math.max(1, accountStates.size)
  136. const highPositionThreshold = avgBalance > 1000 ? 0.02 : avgBalance > 500 ? 0.015 : avgBalance > 200 ? 0.01 : 0.005
  137. const mediumPositionThreshold =
  138. avgBalance > 1000 ? 0.01 : avgBalance > 500 ? 0.008 : avgBalance > 200 ? 0.005 : 0.003
  139. if (totalPosition > highPositionThreshold) {
  140. riskScore += 25
  141. factors.push(`高仓位集中度: ${totalPosition.toFixed(4)} BTC (~${(totalPosition * 65000).toFixed(0)} USDT)`)
  142. recommendations.push('立即执行平仓操作降低风险暴露')
  143. } else if (totalPosition > mediumPositionThreshold) {
  144. riskScore += 12
  145. factors.push(`中等仓位集中度: ${totalPosition.toFixed(4)} BTC (~${(totalPosition * 65000).toFixed(0)} USDT)`)
  146. recommendations.push('考虑部分平仓以控制风险')
  147. }
  148. // 3. 资金安全风险 (权重20%)
  149. if (avgBalance < 50) {
  150. riskScore += 20
  151. factors.push(`低资金余额: $${avgBalance.toFixed(2)}`)
  152. recommendations.push('资金不足,建议停止交易或充值')
  153. } else if (avgBalance < 200) {
  154. riskScore += 10
  155. factors.push(`中低资金余额: $${avgBalance.toFixed(2)}`)
  156. recommendations.push('谨慎交易,限制交易规模')
  157. }
  158. // 4. 交易频率风险 (权重15%)
  159. const sessionTime = (Date.now() - stats.sessionStartTime) / 1000 / 60 // 分钟
  160. const tradeFrequency = sessionTime > 0 ? stats.totalTrades / sessionTime : 0
  161. if (tradeFrequency > 3) {
  162. riskScore += 15
  163. factors.push(`高频交易: ${tradeFrequency.toFixed(2)}笔/分钟`)
  164. recommendations.push('降低交易频率,避免账户被限制')
  165. } else if (tradeFrequency > 2) {
  166. riskScore += 8
  167. factors.push(`中高频交易: ${tradeFrequency.toFixed(2)}笔/分钟`)
  168. }
  169. // 5. Delta中性风险 (权重10%)
  170. const netDelta = Array.from(accountStates.values()).reduce((sum, account) => sum + account.netPosition, 0)
  171. const highDeltaThreshold = avgBalance > 1000 ? 0.008 : avgBalance > 500 ? 0.005 : avgBalance > 200 ? 0.003 : 0.002
  172. const mediumDeltaThreshold = avgBalance > 1000 ? 0.004 : avgBalance > 500 ? 0.003 : avgBalance > 200 ? 0.002 : 0.001
  173. if (Math.abs(netDelta) > highDeltaThreshold) {
  174. riskScore += 10
  175. factors.push(`Delta偏离: ${netDelta.toFixed(4)} BTC (~${(netDelta * 65000).toFixed(0)} USDT)`)
  176. recommendations.push('立即执行对冲操作恢复Delta中性')
  177. } else if (Math.abs(netDelta) > mediumDeltaThreshold) {
  178. riskScore += 5
  179. factors.push(`轻微 Delta偏离: ${netDelta.toFixed(4)} BTC (~${(netDelta * 65000).toFixed(0)} USDT)`)
  180. }
  181. // 6. 基差风险监控 (权重10%)
  182. const basisRisk = await this.assessBasisRisk()
  183. if (basisRisk.riskLevel === 'HIGH') {
  184. riskScore += 10
  185. factors.push(`高基差风险: ${basisRisk.currentBasis?.toFixed(2) || 'N/A'}% 偏离`)
  186. recommendations.push('基差异常,谨慎执行套利交易')
  187. } else if (basisRisk.riskLevel === 'MEDIUM') {
  188. riskScore += 5
  189. factors.push(`中等基差风险: ${basisRisk.currentBasis?.toFixed(2) || 'N/A'}% 偏离`)
  190. recommendations.push('监控基差变化趋势')
  191. } else if (basisRisk.riskLevel === 'CRITICAL') {
  192. riskScore += 15
  193. factors.push(`极端基差风险: ${basisRisk.currentBasis?.toFixed(2) || 'N/A'}% 异常偏离`)
  194. recommendations.push('暂停所有基差相关交易,等待市场恢复正常')
  195. }
  196. // 确定风险等级
  197. let riskLevel
  198. if (riskScore >= 60) {
  199. riskLevel = 'CRITICAL'
  200. recommendations.unshift('紧急停止所有交易并进行风险评估')
  201. } else if (riskScore >= 40) {
  202. riskLevel = 'HIGH'
  203. recommendations.unshift('高度警惕,考虑暂停交易')
  204. } else if (riskScore >= 20) {
  205. riskLevel = 'MEDIUM'
  206. recommendations.unshift('中等风险,加强监控')
  207. } else {
  208. riskLevel = 'LOW'
  209. recommendations.push('风险可控,可继续正常交易')
  210. }
  211. return {
  212. riskScore,
  213. riskLevel,
  214. riskFactors: factors,
  215. recommendations,
  216. }
  217. }
  218. /**
  219. * 计算动态敞口阈值
  220. */
  221. calculateDynamicExposureThreshold() {
  222. const accountStates = this.accountManager.getAllAccountStates()
  223. const accounts = Array.from(accountStates.values())
  224. if (accounts.length === 0) return 0.0003
  225. // 计算最高使用率
  226. let maxUtilizationRate = 0
  227. accounts.forEach(account => {
  228. if (account.lastBalance > 0) {
  229. const utilizationRate = Math.abs(account.lastBalance - account.availableBalance) / account.lastBalance
  230. maxUtilizationRate = Math.max(maxUtilizationRate, utilizationRate)
  231. }
  232. })
  233. // 基础阈值
  234. let baseThreshold = 0.0003
  235. // 根据使用率动态调整阈值
  236. if (maxUtilizationRate >= 0.95) {
  237. baseThreshold = 0.0001
  238. } else if (maxUtilizationRate >= 0.9) {
  239. baseThreshold = 0.00015
  240. } else if (maxUtilizationRate >= 0.8) {
  241. baseThreshold = 0.0002
  242. } else if (maxUtilizationRate >= 0.7) {
  243. baseThreshold = 0.00025
  244. }
  245. return baseThreshold
  246. }
  247. /**
  248. * 更新基差历史数据
  249. */
  250. updateBasisHistory(dataPoint) {
  251. if (!this.basisHistory) {
  252. this.basisHistory = []
  253. }
  254. this.basisHistory.push(dataPoint)
  255. if (this.basisHistory.length > 100) {
  256. this.basisHistory.shift()
  257. }
  258. }
  259. /**
  260. * 获取基差历史数据
  261. */
  262. getBasisHistory() {
  263. return this.basisHistory
  264. }
  265. }