futureConnector.integration.test.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import { FutureConnector } from '../../src/exchanges/binance/FutureConnector'
  2. import { DerivativesTradingUsdsFuturesRestAPI } from '@binance/derivatives-trading-usds-futures'
  3. const describeBinanceIntegration = process.env.TEST_BINANCE === '1' ? describe : describe.skip
  4. // 集成测试 - 需要真实的 API 密钥
  5. // 这些测试会调用真实的 Binance API,请确保有有效的 API 密钥
  6. describeBinanceIntegration('FutureConnector Integration Tests', () => {
  7. let connector: FutureConnector
  8. beforeAll(() => {
  9. // 检查环境变量
  10. if (!process.env.API_KEY || !process.env.API_SECRET) {
  11. console.warn('⚠️ 跳过集成测试:API_KEY 或 API_SECRET 未设置')
  12. return
  13. }
  14. connector = new FutureConnector(process.env.API_KEY, process.env.API_SECRET)
  15. })
  16. // 跳过测试如果没有 API 密钥
  17. const testIfApiKey = process.env.API_KEY && process.env.API_SECRET ? test : test.skip
  18. describe('Account Information', () => {
  19. testIfApiKey(
  20. 'should get account assets info',
  21. async () => {
  22. const assets = await connector.getAssetsInfo()
  23. expect(Array.isArray(assets)).toBe(true)
  24. assets.forEach(asset => {
  25. expect(asset).toHaveProperty('symbol')
  26. expect(asset).toHaveProperty('walletBalance')
  27. expect(Number(asset.walletBalance)).toBeGreaterThan(0)
  28. })
  29. },
  30. 10000,
  31. )
  32. testIfApiKey(
  33. 'should get position info',
  34. async () => {
  35. const positions = await connector.getPositonInfo()
  36. expect(Array.isArray(positions)).toBe(true)
  37. positions.forEach(position => {
  38. expect(position).toHaveProperty('symbol')
  39. expect(position).toHaveProperty('positionAmt')
  40. expect(Number(position.positionAmt)).toBeGreaterThan(0)
  41. })
  42. },
  43. 10000,
  44. )
  45. testIfApiKey(
  46. 'should get all positions',
  47. async () => {
  48. const positions = await connector.getAllPositions()
  49. expect(Array.isArray(positions)).toBe(true)
  50. positions.forEach(position => {
  51. expect(position).toHaveProperty('symbol')
  52. expect(position).toHaveProperty('positionAmt')
  53. expect(position).toHaveProperty('unrealizedPnl')
  54. })
  55. },
  56. 10000,
  57. )
  58. testIfApiKey(
  59. 'should get position by symbol',
  60. async () => {
  61. const position = await connector.getPositionBalanceBySymbol('BTCUSDT')
  62. if (position) {
  63. expect(position).toHaveProperty('symbol', 'BTCUSDT')
  64. expect(position).toHaveProperty('positionAmt')
  65. expect(position).toHaveProperty('unrealizedPnl')
  66. } else {
  67. // 如果没有持仓,应该返回 null
  68. expect(position).toBeNull()
  69. }
  70. },
  71. 10000,
  72. )
  73. })
  74. describe('Order Management', () => {
  75. testIfApiKey(
  76. 'should get current open orders',
  77. async () => {
  78. await expect(connector.getCurrentAllOpenPosition()).resolves.not.toThrow()
  79. },
  80. 10000,
  81. )
  82. testIfApiKey(
  83. 'should get order history',
  84. async () => {
  85. const orders = await connector.getOrderHistory('BTCUSDT', undefined, undefined, 10)
  86. expect(Array.isArray(orders)).toBe(true)
  87. if (orders.length > 0) {
  88. orders.forEach(order => {
  89. expect(order).toHaveProperty('symbol', 'BTCUSDT')
  90. expect(order).toHaveProperty('orderId')
  91. expect(order).toHaveProperty('status')
  92. })
  93. }
  94. },
  95. 10000,
  96. )
  97. testIfApiKey(
  98. 'should get trade history',
  99. async () => {
  100. const trades = await connector.getTradeHistory('BTCUSDT', undefined, undefined, 10)
  101. expect(Array.isArray(trades)).toBe(true)
  102. if (trades.length > 0) {
  103. trades.forEach(trade => {
  104. expect(trade).toHaveProperty('symbol', 'BTCUSDT')
  105. expect(trade).toHaveProperty('id')
  106. expect(trade).toHaveProperty('price')
  107. expect(trade).toHaveProperty('qty')
  108. })
  109. }
  110. },
  111. 10000,
  112. )
  113. })
  114. describe('Trading Operations', () => {
  115. // 注意:这些测试会创建真实的订单,请谨慎使用
  116. // 建议在测试环境中使用小额订单
  117. testIfApiKey.skip(
  118. 'should place and cancel limit order',
  119. async () => {
  120. // 创建限价单
  121. const orderResult = await connector.openLimitOrder(
  122. 'BTCUSDT',
  123. 'long',
  124. 0.001, // 最小数量
  125. 40000, // 远低于市价的价格,确保不会成交
  126. 'GTC',
  127. )
  128. expect(orderResult).toBeDefined()
  129. expect(orderResult).toHaveProperty('orderId')
  130. expect(orderResult).toHaveProperty('status')
  131. // 撤销订单
  132. if (orderResult && orderResult.orderId) {
  133. const cancelResult = await connector.cancelOrder('BTCUSDT', orderResult.orderId)
  134. expect(cancelResult).toBeDefined()
  135. }
  136. },
  137. 30000,
  138. )
  139. testIfApiKey.skip(
  140. 'should place market order',
  141. async () => {
  142. // 市价单会立即成交,请谨慎使用
  143. const orderResult = await connector.openMarketOrder(
  144. 'BTCUSDT',
  145. 'long',
  146. 0.001, // 最小数量
  147. )
  148. expect(orderResult).toBeDefined()
  149. expect(orderResult).toHaveProperty('orderId')
  150. expect(orderResult).toHaveProperty('status')
  151. },
  152. 30000,
  153. )
  154. testIfApiKey.skip(
  155. 'should place stop order',
  156. async () => {
  157. // 止损单,设置远低于市价的价格
  158. const orderResult = await connector.openStopOrder(
  159. 'BTCUSDT',
  160. 'long',
  161. 0.001,
  162. 30000, // 远低于市价的止损价格
  163. 'STOP_MARKET',
  164. )
  165. expect(orderResult).toBeDefined()
  166. expect(orderResult).toHaveProperty('orderId')
  167. expect(orderResult).toHaveProperty('status')
  168. // 撤销订单
  169. if (orderResult && orderResult.orderId) {
  170. const cancelResult = await connector.cancelOrder('BTCUSDT', orderResult.orderId)
  171. expect(cancelResult).toBeDefined()
  172. }
  173. },
  174. 30000,
  175. )
  176. })
  177. describe('Account Settings', () => {
  178. testIfApiKey.skip(
  179. 'should set leverage',
  180. async () => {
  181. const result = await connector.setLeverage('BTCUSDT', 10)
  182. expect(result).toBeDefined()
  183. expect(result).toHaveProperty('leverage')
  184. expect(result).toHaveProperty('maxNotionalValue')
  185. },
  186. 10000,
  187. )
  188. testIfApiKey.skip(
  189. 'should set margin type',
  190. async () => {
  191. const result = await connector.setMarginType(
  192. 'BTCUSDT',
  193. DerivativesTradingUsdsFuturesRestAPI.ChangeMarginTypeMarginTypeEnum.ISOLATED,
  194. )
  195. expect(result).toBeDefined()
  196. expect(result).toHaveProperty('code')
  197. },
  198. 10000,
  199. )
  200. })
  201. describe('Error Handling', () => {
  202. testIfApiKey(
  203. 'should handle invalid symbol gracefully',
  204. async () => {
  205. const position = await connector.getPositionBalanceBySymbol('INVALID_SYMBOL')
  206. expect(position).toBeNull()
  207. },
  208. 10000,
  209. )
  210. testIfApiKey(
  211. 'should handle invalid order parameters',
  212. async () => {
  213. // 测试无效的订单参数
  214. const result = await connector.openPosition(
  215. 'INVALID_SYMBOL',
  216. DerivativesTradingUsdsFuturesRestAPI.NewOrderSideEnum.BUY,
  217. 0,
  218. 0,
  219. )
  220. // 应该返回 null 或抛出错误
  221. expect(result).toBeNull()
  222. },
  223. 10000,
  224. )
  225. })
  226. })