testHelpers.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. import { DerivativesTradingUsdsFuturesRestAPI } from '@binance/derivatives-trading-usds-futures'
  2. /**
  3. * 测试辅助工具类
  4. */
  5. export class TestHelpers {
  6. /**
  7. * 生成模拟的账户资产数据
  8. */
  9. static createMockAssets() {
  10. return [
  11. {
  12. symbol: 'USDT',
  13. walletBalance: '1000.0',
  14. unrealizedPnl: '0.0',
  15. marginBalance: '1000.0',
  16. maintMargin: '0.0',
  17. initialMargin: '0.0',
  18. positionInitialMargin: '0.0',
  19. openOrderInitialMargin: '0.0',
  20. maxWithdrawAmount: '1000.0',
  21. crossWalletBalance: '1000.0',
  22. crossUnPnl: '0.0',
  23. availableBalance: '1000.0',
  24. marginAvailable: true,
  25. updateTime: 0,
  26. },
  27. {
  28. symbol: 'BTC',
  29. walletBalance: '0.1',
  30. unrealizedPnl: '10.5',
  31. marginBalance: '10.6',
  32. maintMargin: '0.1',
  33. initialMargin: '0.1',
  34. positionInitialMargin: '0.1',
  35. openOrderInitialMargin: '0.0',
  36. maxWithdrawAmount: '10.5',
  37. crossWalletBalance: '0.1',
  38. crossUnPnl: '10.5',
  39. availableBalance: '10.5',
  40. marginAvailable: true,
  41. updateTime: 0,
  42. },
  43. {
  44. symbol: 'ETH',
  45. walletBalance: '5.0',
  46. unrealizedPnl: '25.0',
  47. marginBalance: '30.0',
  48. maintMargin: '0.5',
  49. initialMargin: '0.5',
  50. positionInitialMargin: '0.5',
  51. openOrderInitialMargin: '0.0',
  52. maxWithdrawAmount: '29.5',
  53. crossWalletBalance: '5.0',
  54. crossUnPnl: '25.0',
  55. availableBalance: '29.5',
  56. marginAvailable: true,
  57. updateTime: 0,
  58. },
  59. ]
  60. }
  61. /**
  62. * 生成模拟的持仓数据
  63. */
  64. static createMockPositions() {
  65. return [
  66. {
  67. symbol: 'BTCUSDT',
  68. initialMargin: '0.1',
  69. maintMargin: '0.1',
  70. unrealizedPnl: '10.5',
  71. positionInitialMargin: '0.1',
  72. openOrderInitialMargin: '0.0',
  73. leverage: '10',
  74. isolated: false,
  75. entryPrice: '50000.0',
  76. maxNotional: '1000000',
  77. bidNotional: '0',
  78. askNotional: '0',
  79. positionSide: 'BOTH',
  80. positionAmt: '0.1',
  81. updateTime: 0,
  82. },
  83. {
  84. symbol: 'ETHUSDT',
  85. initialMargin: '0.0',
  86. maintMargin: '0.0',
  87. unrealizedPnl: '0.0',
  88. positionInitialMargin: '0.0',
  89. openOrderInitialMargin: '0.0',
  90. leverage: '10',
  91. isolated: false,
  92. entryPrice: '0.0',
  93. maxNotional: '1000000',
  94. bidNotional: '0',
  95. askNotional: '0',
  96. positionSide: 'BOTH',
  97. positionAmt: '0.0',
  98. updateTime: 0,
  99. },
  100. {
  101. symbol: 'ADAUSDT',
  102. initialMargin: '0.5',
  103. maintMargin: '0.5',
  104. unrealizedPnl: '-5.2',
  105. positionInitialMargin: '0.5',
  106. openOrderInitialMargin: '0.0',
  107. leverage: '10',
  108. isolated: false,
  109. entryPrice: '0.5',
  110. maxNotional: '1000000',
  111. bidNotional: '0',
  112. askNotional: '0',
  113. positionSide: 'BOTH',
  114. positionAmt: '-100.0',
  115. updateTime: 0,
  116. },
  117. ]
  118. }
  119. /**
  120. * 生成模拟的订单数据
  121. */
  122. static createMockOrders() {
  123. return [
  124. {
  125. orderId: 12345,
  126. symbol: 'BTCUSDT',
  127. status: 'NEW',
  128. clientOrderId: 'test_order_123',
  129. price: '50000',
  130. avgPrice: '0',
  131. origQty: '0.001',
  132. executedQty: '0',
  133. cumQuote: '0',
  134. timeInForce: 'GTC',
  135. type: 'LIMIT',
  136. reduceOnly: false,
  137. closePosition: false,
  138. side: 'BUY',
  139. positionSide: 'LONG',
  140. stopPrice: '0',
  141. workingType: 'CONTRACT_PRICE',
  142. priceProtect: false,
  143. origType: 'LIMIT',
  144. time: 1640995200000,
  145. updateTime: 1640995200000,
  146. },
  147. {
  148. orderId: 12346,
  149. symbol: 'ETHUSDT',
  150. status: 'FILLED',
  151. clientOrderId: 'test_order_124',
  152. price: '3000',
  153. avgPrice: '3000',
  154. origQty: '0.01',
  155. executedQty: '0.01',
  156. cumQuote: '30',
  157. timeInForce: 'GTC',
  158. type: 'MARKET',
  159. reduceOnly: false,
  160. closePosition: false,
  161. side: 'BUY',
  162. positionSide: 'LONG',
  163. stopPrice: '0',
  164. workingType: 'CONTRACT_PRICE',
  165. priceProtect: false,
  166. origType: 'MARKET',
  167. time: 1640995200000,
  168. updateTime: 1640995200000,
  169. },
  170. ]
  171. }
  172. /**
  173. * 生成模拟的成交数据
  174. */
  175. static createMockTrades() {
  176. return [
  177. {
  178. id: 12365,
  179. symbol: 'BTCUSDT',
  180. orderId: 12345,
  181. pair: 'BTCUSDT',
  182. side: 'BUY',
  183. price: '50000',
  184. qty: '0.001',
  185. realizedPnl: '0',
  186. marginAsset: 'USDT',
  187. baseQty: '0.001',
  188. commission: '0.025',
  189. commissionAsset: 'USDT',
  190. time: 1640995200000,
  191. positionSide: 'LONG',
  192. maker: false,
  193. buyer: true,
  194. },
  195. {
  196. id: 12366,
  197. symbol: 'ETHUSDT',
  198. orderId: 12346,
  199. pair: 'ETHUSDT',
  200. side: 'BUY',
  201. price: '3000',
  202. qty: '0.01',
  203. realizedPnl: '0',
  204. marginAsset: 'USDT',
  205. baseQty: '0.01',
  206. commission: '0.15',
  207. commissionAsset: 'USDT',
  208. time: 1640995200000,
  209. positionSide: 'LONG',
  210. maker: false,
  211. buyer: true,
  212. },
  213. ]
  214. }
  215. /**
  216. * 生成模拟的订单结果
  217. */
  218. static createMockOrderResult(orderId: number = 12345, status: string = 'NEW') {
  219. return {
  220. orderId,
  221. symbol: 'BTCUSDT',
  222. status,
  223. clientOrderId: `test_order_${orderId}`,
  224. price: '50000',
  225. avgPrice: '0',
  226. origQty: '0.001',
  227. executedQty: '0',
  228. cumQuote: '0',
  229. timeInForce: 'GTC',
  230. type: 'LIMIT',
  231. reduceOnly: false,
  232. closePosition: false,
  233. side: 'BUY',
  234. positionSide: 'LONG',
  235. stopPrice: '0',
  236. workingType: 'CONTRACT_PRICE',
  237. priceProtect: false,
  238. origType: 'LIMIT',
  239. time: Date.now(),
  240. updateTime: Date.now(),
  241. }
  242. }
  243. /**
  244. * 生成模拟的 API 响应
  245. */
  246. static createMockApiResponse(data: any) {
  247. return {
  248. data: jest.fn().mockResolvedValue(data),
  249. }
  250. }
  251. /**
  252. * 生成模拟的 API 错误
  253. */
  254. static createMockApiError(message: string = 'API Error', code: number = -1000) {
  255. const error = new Error(message) as any
  256. error.code = code
  257. error.msg = message
  258. return error
  259. }
  260. /**
  261. * 验证订单参数
  262. */
  263. static validateOrderParams(params: any, expectedParams: any) {
  264. expect(params).toMatchObject(expectedParams)
  265. // 验证必需字段
  266. expect(params).toHaveProperty('symbol')
  267. expect(params).toHaveProperty('side')
  268. expect(params).toHaveProperty('type')
  269. expect(params).toHaveProperty('timeInForce')
  270. expect(params).toHaveProperty('quantity')
  271. expect(params).toHaveProperty('price')
  272. }
  273. /**
  274. * 验证资产数据格式
  275. */
  276. static validateAssetData(asset: any) {
  277. expect(asset).toHaveProperty('symbol')
  278. expect(asset).toHaveProperty('walletBalance')
  279. expect(asset).toHaveProperty('unrealizedPnl')
  280. expect(asset).toHaveProperty('marginBalance')
  281. expect(asset).toHaveProperty('availableBalance')
  282. expect(typeof asset.symbol).toBe('string')
  283. expect(typeof asset.walletBalance).toBe('string')
  284. }
  285. /**
  286. * 验证持仓数据格式
  287. */
  288. static validatePositionData(position: any) {
  289. expect(position).toHaveProperty('symbol')
  290. expect(position).toHaveProperty('positionAmt')
  291. expect(position).toHaveProperty('unrealizedPnl')
  292. expect(position).toHaveProperty('entryPrice')
  293. expect(position).toHaveProperty('leverage')
  294. expect(typeof position.symbol).toBe('string')
  295. expect(typeof position.positionAmt).toBe('string')
  296. }
  297. /**
  298. * 验证订单数据格式
  299. */
  300. static validateOrderData(order: any) {
  301. expect(order).toHaveProperty('orderId')
  302. expect(order).toHaveProperty('symbol')
  303. expect(order).toHaveProperty('status')
  304. expect(order).toHaveProperty('side')
  305. expect(order).toHaveProperty('type')
  306. expect(typeof order.orderId).toBe('number')
  307. expect(typeof order.symbol).toBe('string')
  308. expect(typeof order.status).toBe('string')
  309. }
  310. /**
  311. * 验证成交数据格式
  312. */
  313. static validateTradeData(trade: any) {
  314. expect(trade).toHaveProperty('id')
  315. expect(trade).toHaveProperty('symbol')
  316. expect(trade).toHaveProperty('orderId')
  317. expect(trade).toHaveProperty('price')
  318. expect(trade).toHaveProperty('qty')
  319. expect(trade).toHaveProperty('side')
  320. expect(typeof trade.id).toBe('number')
  321. expect(typeof trade.symbol).toBe('string')
  322. expect(typeof trade.price).toBe('string')
  323. }
  324. /**
  325. * 生成测试用的交易对列表
  326. */
  327. static getTestSymbols() {
  328. return ['BTCUSDT', 'ETHUSDT', 'ADAUSDT', 'BNBUSDT', 'SOLUSDT']
  329. }
  330. /**
  331. * 生成测试用的价格范围
  332. */
  333. static getTestPriceRange(symbol: string) {
  334. const priceRanges: { [key: string]: { min: number; max: number } } = {
  335. BTCUSDT: { min: 40000, max: 60000 },
  336. ETHUSDT: { min: 2000, max: 4000 },
  337. ADAUSDT: { min: 0.3, max: 0.7 },
  338. BNBUSDT: { min: 200, max: 400 },
  339. SOLUSDT: { min: 50, max: 150 },
  340. }
  341. return priceRanges[symbol] || { min: 1, max: 100 }
  342. }
  343. /**
  344. * 生成测试用的数量范围
  345. */
  346. static getTestQuantityRange(symbol: string) {
  347. const quantityRanges: { [key: string]: { min: number; max: number } } = {
  348. BTCUSDT: { min: 0.001, max: 0.01 },
  349. ETHUSDT: { min: 0.01, max: 0.1 },
  350. ADAUSDT: { min: 10, max: 1000 },
  351. BNBUSDT: { min: 0.1, max: 1 },
  352. SOLUSDT: { min: 0.1, max: 10 },
  353. }
  354. return quantityRanges[symbol] || { min: 0.001, max: 1 }
  355. }
  356. /**
  357. * 生成随机价格
  358. */
  359. static generateRandomPrice(symbol: string): number {
  360. const range = this.getTestPriceRange(symbol)
  361. return Math.random() * (range.max - range.min) + range.min
  362. }
  363. /**
  364. * 生成随机数量
  365. */
  366. static generateRandomQuantity(symbol: string): number {
  367. const range = this.getTestQuantityRange(symbol)
  368. return Math.random() * (range.max - range.min) + range.min
  369. }
  370. /**
  371. * 等待指定时间
  372. */
  373. static async wait(ms: number): Promise<void> {
  374. return new Promise(resolve => setTimeout(resolve, ms))
  375. }
  376. /**
  377. * 重试函数
  378. */
  379. static async retry<T>(fn: () => Promise<T>, maxAttempts: number = 3, delay: number = 1000): Promise<T> {
  380. let lastError: Error
  381. for (let attempt = 1; attempt <= maxAttempts; attempt++) {
  382. try {
  383. return await fn()
  384. } catch (error) {
  385. lastError = error as Error
  386. if (attempt < maxAttempts) {
  387. await this.wait(delay * attempt)
  388. }
  389. }
  390. }
  391. throw lastError!
  392. }
  393. }