test-advanced.ts 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #!/usr/bin/env tsx
  2. /**
  3. * 高级功能测试套件
  4. * 测试4: WebSocket断线后REST API降级
  5. * 测试5: RiskManager风险告警触发
  6. * 测试6: Delta中性验证 (模拟账户配对交易)
  7. */
  8. import { MarketDataManager } from '../src/services/MarketDataManager';
  9. import { RiskManager, RiskManagerConfig } from '../src/core/RiskManager';
  10. import { Account } from '../src/models/Account';
  11. import { PacificaSigningClient } from '../src/services/PacificaSigningClient';
  12. import { readFileSync } from 'fs';
  13. console.log('🧪 开始高级功能测试...\n');
  14. let testsPassed = 0;
  15. let testsFailed = 0;
  16. // 测试4: WebSocket降级测试
  17. async function testWebSocketFailover(): Promise<boolean> {
  18. console.log('🔌 测试4: WebSocket断线与REST API降级');
  19. try {
  20. const marketDataManager = new MarketDataManager();
  21. let priceFromWS = false;
  22. let priceValue = 0;
  23. marketDataManager.on('price_update', (priceData) => {
  24. if (priceData.symbol === 'BTC') {
  25. priceFromWS = true;
  26. priceValue = typeof priceData.mark === 'number' ? priceData.mark : parseFloat(priceData.mark);
  27. }
  28. });
  29. await marketDataManager.initialize();
  30. console.log(' ✅ MarketDataManager初始化成功');
  31. // 等待WebSocket价格
  32. await new Promise(resolve => setTimeout(resolve, 3000));
  33. if (priceFromWS) {
  34. console.log(` ✅ WebSocket价格正常: $${priceValue.toFixed(2)}`);
  35. } else {
  36. console.log(' ⚠️ 未收到WebSocket价格');
  37. }
  38. // 模拟WebSocket断开
  39. console.log(' 🔌 模拟WebSocket断开...');
  40. await marketDataManager.disconnect();
  41. await new Promise(resolve => setTimeout(resolve, 1000));
  42. // 测试REST API降级
  43. console.log(' 🔄 测试REST API降级方案...');
  44. const accountsData = JSON.parse(readFileSync('./config/accounts.json', 'utf-8'));
  45. if (accountsData.length === 0) {
  46. console.log(' ❌ 没有可用账户配置\n');
  47. return false;
  48. }
  49. const privateKey = accountsData[0].privateKey;
  50. const pacificaClient = new PacificaSigningClient(privateKey);
  51. try {
  52. const prices = await pacificaClient.getPrices();
  53. const btcPrice = prices.data.find((p: any) => p.symbol === 'BTC');
  54. if (btcPrice && btcPrice.mark) {
  55. const restPrice = parseFloat(btcPrice.mark);
  56. console.log(` ✅ REST API价格: $${restPrice.toFixed(2)}`);
  57. if (priceFromWS) {
  58. const priceDiff = Math.abs(restPrice - priceValue);
  59. const priceDiffPercent = (priceDiff / priceValue) * 100;
  60. console.log(` 📊 价格差异: $${priceDiff.toFixed(2)} (${priceDiffPercent.toFixed(3)}%)`);
  61. }
  62. console.log(' ✅ 测试4通过: 降级机制正常\n');
  63. return true;
  64. } else {
  65. console.log(' ❌ REST API未返回BTC价格\n');
  66. return false;
  67. }
  68. } catch (error) {
  69. console.log(` ❌ REST API调用失败: ${error instanceof Error ? error.message : '未知错误'}\n`);
  70. return false;
  71. }
  72. } catch (error) {
  73. console.log(` ❌ 测试4失败: ${error instanceof Error ? error.message : '未知错误'}\n`);
  74. return false;
  75. }
  76. }
  77. // 测试5: RiskManager风险告警
  78. async function testRiskManagerBreach(): Promise<boolean> {
  79. console.log('⚠️ 测试5: RiskManager风险告警触发');
  80. try {
  81. const riskConfig: RiskManagerConfig = {
  82. maxTotalVolume: 10,
  83. maxNetExposure: 0.01,
  84. maxDailyLoss: 1000,
  85. positionLimit: 0.1, // 设置很小的限制用于触发告警
  86. stopLossThreshold: 500,
  87. monitoringInterval: 60000
  88. };
  89. const riskManager = new RiskManager(riskConfig);
  90. let breachDetected = false;
  91. let breachType = '';
  92. riskManager.on('breach_detected', (breach) => {
  93. breachDetected = true;
  94. breachType = breach.type;
  95. console.log(` ⚠️ 检测到风险告警: ${breach.type} (严重程度: ${breach.severity})`);
  96. });
  97. await riskManager.initialize();
  98. const sessionId = 'test_risk_' + Date.now();
  99. await riskManager.startMonitoring(sessionId);
  100. console.log(' ✅ RiskManager已启动');
  101. // 测试1: 正常仓位 (应该通过)
  102. const normalBreach = await riskManager.checkPositionSizeRisk(
  103. sessionId,
  104. 'test_account_1',
  105. 0.05 // 小于0.1限制
  106. );
  107. if (normalBreach === null) {
  108. console.log(' ✅ 正常仓位检查通过 (0.05 < 0.1)');
  109. } else {
  110. console.log(' ❌ 正常仓位被误判为风险');
  111. }
  112. // 测试2: 超限仓位 (应该触发告警)
  113. const largeBreach = await riskManager.checkPositionSizeRisk(
  114. sessionId,
  115. 'test_account_2',
  116. 0.15 // 大于0.1限制
  117. );
  118. if (largeBreach !== null) {
  119. console.log(` ✅ 超限仓位被拦截 (0.15 > 0.1): ${largeBreach.type}`);
  120. breachDetected = true;
  121. breachType = largeBreach.type;
  122. } else {
  123. console.log(' ⚠️ 超限仓位未被检测到');
  124. }
  125. await riskManager.stopMonitoring(sessionId);
  126. await riskManager.shutdown();
  127. if (normalBreach === null && largeBreach !== null) {
  128. console.log(' ✅ 测试5通过: 风险控制正常工作\n');
  129. return true;
  130. } else {
  131. console.log(' ❌ 测试5失败: 风险检查逻辑有误\n');
  132. return false;
  133. }
  134. } catch (error) {
  135. console.log(` ❌ 测试5失败: ${error instanceof Error ? error.message : '未知错误'}\n`);
  136. return false;
  137. }
  138. }
  139. // 测试6: Delta中性验证
  140. async function testDeltaNeutrality(): Promise<boolean> {
  141. console.log('⚖️ 测试6: Delta中性验证 (模拟配对交易)');
  142. try {
  143. // 加载账户配置
  144. const accountsData = JSON.parse(readFileSync('./config/accounts.json', 'utf-8'));
  145. if (accountsData.length < 2) {
  146. console.log(' ❌ 需要至少2个账户进行测试\n');
  147. return false;
  148. }
  149. // 创建账户实例
  150. const accounts = accountsData.map((data: any) => new Account({
  151. ...data,
  152. apiKey: data.apiKey || 'test_api_key',
  153. balance: { total: 1000, available: 1000, used: 0 },
  154. positions: []
  155. }));
  156. console.log(` 📊 使用${accounts.length}个账户进行测试`);
  157. // 创建账户配对
  158. const accountPairs: Array<[Account, Account]> = [];
  159. for (let i = 0; i < accounts.length - 1; i += 2) {
  160. accountPairs.push([accounts[i], accounts[i + 1]]);
  161. }
  162. console.log(` 🔗 创建${accountPairs.length}对账户`);
  163. // 模拟配对交易
  164. interface MockTrade {
  165. accountId: string;
  166. side: 'buy' | 'sell';
  167. size: number;
  168. price: number;
  169. }
  170. const mockTrades: MockTrade[] = [];
  171. const tradeSize = 0.01; // 0.01 BTC
  172. const tradePrice = 100000; // $100,000
  173. for (const [buyAccount, sellAccount] of accountPairs) {
  174. // 买方交易
  175. mockTrades.push({
  176. accountId: buyAccount.getId(),
  177. side: 'buy',
  178. size: tradeSize,
  179. price: tradePrice
  180. });
  181. // 卖方交易
  182. mockTrades.push({
  183. accountId: sellAccount.getId(),
  184. side: 'sell',
  185. size: tradeSize,
  186. price: tradePrice
  187. });
  188. console.log(` 📈 配对${accountPairs.indexOf([buyAccount, sellAccount]) + 1}: ` +
  189. `${buyAccount.getId().slice(0,8)} 买入 ${tradeSize} BTC / ` +
  190. `${sellAccount.getId().slice(0,8)} 卖出 ${tradeSize} BTC`);
  191. }
  192. // 计算净Delta
  193. let totalBuyVolume = 0;
  194. let totalSellVolume = 0;
  195. mockTrades.forEach(trade => {
  196. if (trade.side === 'buy') {
  197. totalBuyVolume += trade.size;
  198. } else {
  199. totalSellVolume += trade.size;
  200. }
  201. });
  202. const netDelta = totalBuyVolume - totalSellVolume;
  203. const netDeltaPercent = Math.abs(netDelta / totalBuyVolume) * 100;
  204. console.log(` 📊 总买入: ${totalBuyVolume.toFixed(6)} BTC`);
  205. console.log(` 📊 总卖出: ${totalSellVolume.toFixed(6)} BTC`);
  206. console.log(` 📊 净Delta: ${netDelta.toFixed(6)} BTC (${netDeltaPercent.toFixed(4)}%)`);
  207. // 验证Delta中性 (容差0.0001%)
  208. if (Math.abs(netDeltaPercent) < 0.0001) {
  209. console.log(' ✅ Delta中性验证通过: 净仓位为零');
  210. console.log(' ✅ 测试6通过: 配对交易逻辑正确\n');
  211. return true;
  212. } else {
  213. console.log(` ❌ Delta不中性: ${netDeltaPercent.toFixed(4)}% 偏差`);
  214. console.log(' ❌ 测试6失败: 配对交易逻辑有误\n');
  215. return false;
  216. }
  217. } catch (error) {
  218. console.log(` ❌ 测试6失败: ${error instanceof Error ? error.message : '未知错误'}\n`);
  219. return false;
  220. }
  221. }
  222. // 主测试流程
  223. async function runAdvancedTests() {
  224. console.log('='.repeat(60));
  225. console.log(' P0高级功能测试套件');
  226. console.log('='.repeat(60) + '\n');
  227. // 测试4: WebSocket降级
  228. if (await testWebSocketFailover()) {
  229. testsPassed++;
  230. } else {
  231. testsFailed++;
  232. }
  233. // 测试5: 风险告警
  234. if (await testRiskManagerBreach()) {
  235. testsPassed++;
  236. } else {
  237. testsFailed++;
  238. }
  239. // 测试6: Delta中性
  240. if (await testDeltaNeutrality()) {
  241. testsPassed++;
  242. } else {
  243. testsFailed++;
  244. }
  245. // 输出结果
  246. console.log('='.repeat(60));
  247. console.log(' 测试结果');
  248. console.log('='.repeat(60));
  249. console.log(`✅ 通过: ${testsPassed}/3`);
  250. console.log(`❌ 失败: ${testsFailed}/3`);
  251. console.log(`📊 成功率: ${((testsPassed / 3) * 100).toFixed(1)}%`);
  252. console.log('='.repeat(60) + '\n');
  253. if (testsPassed === 3) {
  254. console.log('🎉 所有高级测试通过! 系统功能完整。');
  255. console.log('🚀 可以开始生产环境部署。\n');
  256. process.exit(0);
  257. } else {
  258. console.log('⚠️ 部分测试失败,请检查上述错误信息。\n');
  259. process.exit(1);
  260. }
  261. }
  262. // 运行测试
  263. runAdvancedTests().catch((error) => {
  264. console.error('💥 测试执行失败:', error);
  265. process.exit(1);
  266. });