one-pro.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. const OneTask = require('../libs/one-task')
  2. const OneInch = require('../libs/web3/1inch')
  3. const BinanceSpot = require('../libs/binance/binance-spot')
  4. const Config = require('../config/config')
  5. const PrivateConfig = require('../PrivateConfig')
  6. const NumKit = require('../kit/num-kit')
  7. const TimeKit = require('../kit/time-kit')
  8. const TableKit = require('../kit/table-kit')
  9. const BinanceKit = require("../libs/binance/binance-kit");
  10. const orderHandler = async function(context, task) {
  11. const fileLogger = task.fileLogger
  12. const tokenMap = context.tokenMap
  13. const binanceSpot = context.binanceSpot
  14. const accountAssetMap = context.accountAssetMap
  15. // 逐对处理交易信息
  16. for (const tokenHash of Object.keys(tokenMap)) {
  17. const token = tokenMap[tokenHash]
  18. const pair = token.exchange.pair
  19. // 价格非法判定
  20. if (!token.BinancePrice || !token.OneInchPrice) continue;
  21. // 更新token的实际余额
  22. // token.orderAmount = NumKit.getSubFloat(accountAssetMap[token.exchange.symbol], token.exchange.lotSize)
  23. // 卖出逻辑判定
  24. if (token.orderPrice && token.orderAmount > Math.pow(10, -token.exchange.lotSize)) {
  25. if (token.BinancePrice > token.orderPrice) {
  26. // 止盈逻辑
  27. const isStopWin = token.BinancePrice > (token.orderPrice * (100 + PrivateConfig.stopWinPercentage) / 100)
  28. if (isStopWin) {
  29. const sellRst = await binanceSpot.sell(pair, -1, token.orderAmount)
  30. if (sellRst.executedQty) {
  31. const cummulativeQuoteQty = NumKit.getSubFloat(sellRst.cummulativeQuoteQty, 6)
  32. const executedQty = NumKit.getSubFloat(sellRst.executedQty, token.exchange.lotSize)
  33. const price = cummulativeQuoteQty / executedQty
  34. fileLogger.info(`[盈+]${pair}, price: ${token.orderPrice}->${price}, amount: ${token.orderAmount}.`)
  35. token.orderPrice = undefined
  36. token.nextHandleTime = new Date().getTime() + PrivateConfig.stopWinHandleSpaceHours * (60 * 60 * 1000)
  37. } else {
  38. token.orderPrice = undefined
  39. token.nextHandleTime = new Date().getTime() + PrivateConfig.stopWinHandleSpaceHours * (60 * 60 * 1000)
  40. fileLogger.error(`[止盈失败]${pair}, ${JSON.stringify(sellRst)}`)
  41. }
  42. }
  43. } else {
  44. // 止损逻辑
  45. const isStopLoss = token.BinancePrice < (token.orderPrice * (100 - PrivateConfig.stopLossPercentage) / 100)
  46. if (isStopLoss) {
  47. const sellRst = await binanceSpot.sell(pair, -1, token.orderAmount)
  48. if (sellRst.executedQty) {
  49. const cummulativeQuoteQty = NumKit.getSubFloat(sellRst.cummulativeQuoteQty, 6)
  50. const executedQty = NumKit.getSubFloat(sellRst.executedQty, token.exchange.lotSize)
  51. const price = cummulativeQuoteQty / executedQty
  52. fileLogger.info(`[损-]${pair}, price: ${token.orderPrice}->${price}, amount: ${token.orderAmount}.`)
  53. token.orderPrice = undefined
  54. token.nextHandleTime = new Date().getTime() + PrivateConfig.stopLossHandleSpaceHours * (60 * 60 * 1000)
  55. } else {
  56. token.orderPrice = undefined
  57. token.nextHandleTime = new Date().getTime() + PrivateConfig.stopLossHandleSpaceHours * (60 * 60 * 1000)
  58. fileLogger.error(`[止损失败]${pair}, ${JSON.stringify(sellRst)}`)
  59. }
  60. }
  61. }
  62. } else if (token.isLong) {
  63. // 1. 获取base资产数量
  64. const baseAssetAmount = accountAssetMap[Config.baseIerc20Token.symbol]
  65. // 判断余额是否够下单
  66. if (PrivateConfig.baseTokenAmount > baseAssetAmount) {
  67. fileLogger.info(`[余额不足]${pair}, 需要: ${PrivateConfig.baseTokenAmount}, 剩余: ${baseAssetAmount}.`)
  68. token.nextHandleTime = new Date().getTime() + PrivateConfig.stopLossHandleSpaceHours * (60 * 60 * 1000)
  69. continue;
  70. }
  71. // 2. 下单获取成交数量以及平均价格
  72. const buyRst = await binanceSpot.buy(pair, -1, PrivateConfig.baseTokenAmount)
  73. if (buyRst.executedQty) {
  74. const cummulativeQuoteQty = NumKit.getSubFloat(buyRst.cummulativeQuoteQty, 6)
  75. // 计算扣除手续费后的实际成交数量
  76. let executedQty = 0
  77. for (const fill of buyRst.fills) {
  78. executedQty += parseFloat(fill.qty)
  79. // 扣除支付的手续费
  80. if (fill.commissionAsset === token.exchange.symbol) {
  81. executedQty -= parseFloat(fill.commission)
  82. }
  83. }
  84. token.orderAmount = NumKit.getSubFloat(executedQty, token.exchange.lotSize)
  85. token.orderPrice = NumKit.getSubFloat(cummulativeQuoteQty / executedQty, token.exchange.priceTick)
  86. fileLogger.info(`[单]${pair}, volume:${cummulativeQuoteQty}, 买入${executedQty}, 均价${token.orderPrice}.`)
  87. accountAssetMap[Config.baseIerc20Token.symbol] = accountAssetMap[Config.baseIerc20Token.symbol] - cummulativeQuoteQty
  88. } else {
  89. fileLogger.error(`[下单失败]${JSON.stringify(buyRst)}`)
  90. }
  91. }
  92. }
  93. }
  94. const table = new TableKit(['pair', '1inch', 'binance', 'order price', 'profit(%)', 'next time'], 20)
  95. const showInfo = function(context, task) {
  96. const logger = task.logger
  97. const tokenMap = context.tokenMap
  98. const accountAssetMap = context.accountAssetMap
  99. table.printTitles()
  100. Object.keys(tokenMap).forEach((tokenHash) => {
  101. const token = tokenMap[tokenHash]
  102. const pair = token.exchange.pair
  103. const OneInchPrice = token.OneInchPrice ? token.OneInchPrice : NaN
  104. const BinancePrice = token.BinancePrice ? token.BinancePrice : NaN
  105. const DiffPrice = token.DiffPrice
  106. const percentage = NumKit.getSubFloat((DiffPrice / OneInchPrice) * 100, 2)
  107. const orderPrice = token.orderPrice ? token.orderPrice : ''
  108. const orderPercentage = orderPrice ? NumKit.getSubFloat(((BinancePrice - orderPrice) / orderPrice) * 100, 2) : ''
  109. const nextTimeStr = token.nextHandleTime ? TimeKit.getTimeByMillisecond(token.nextHandleTime) : ''
  110. // 价格非法判定
  111. const priceCondition = (() => {
  112. return OneInchPrice && BinancePrice
  113. })()
  114. const rows = [pair.toString(), OneInchPrice.toString(), BinancePrice.toString(),
  115. orderPrice.toString(), orderPercentage.toString(), nextTimeStr]
  116. // 识别到在拉盘
  117. token.isLong = (() => {
  118. const percentageCondition = percentage > PrivateConfig.percentageLimit
  119. const isNoPrevHandleTime = !token.nextHandleTime
  120. const isTimeCover = new Date().getTime() > token.nextHandleTime
  121. const timeCondition = isNoPrevHandleTime || isTimeCover
  122. return priceCondition && percentageCondition && timeCondition
  123. })()
  124. // 打印表格
  125. table.showLine(rows, undefined)
  126. })
  127. table.printEndLine(logger)
  128. logger.info(`${Config.baseIerc20Token.symbol} asset amount: ${accountAssetMap[Config.baseIerc20Token.symbol]}.`)
  129. logger.info('')
  130. }
  131. const priceHandler = async function(context, task) {
  132. const tokenMap = context.tokenMap
  133. const tokenContractAddressList = Object.keys(tokenMap)
  134. for (const tokenHash of tokenContractAddressList) {
  135. const toToken = tokenMap[tokenHash]
  136. const priceTick = toToken.exchange.priceTick
  137. const fromIerc20Token = Config.baseIerc20Token
  138. const amount = PrivateConfig.baseTokenAmount
  139. const OneInchPrice = NumKit.getSubFloat(await OneInch.price(fromIerc20Token.contract, tokenHash, amount), priceTick)
  140. const BinancePrice = NumKit.getSubFloat(await BinanceSpot.realPrice(toToken.exchange.pair), priceTick)
  141. toToken.OneInchPrice = OneInchPrice
  142. toToken.BinancePrice = BinancePrice
  143. toToken.DiffPrice = BinancePrice - OneInchPrice
  144. if ((() => {
  145. return Math.abs(toToken.DiffPrice) < Math.pow(10, -priceTick)
  146. })()) {
  147. toToken.DiffPrice = 0
  148. } {
  149. toToken.DiffPrice = NumKit.getSubFloat(toToken.DiffPrice, priceTick)
  150. }
  151. }
  152. }
  153. const accountHandler = async function(context, task) {
  154. const accountInfoRst = await context.binanceSpot.accountInfo()
  155. context.accountAssetMap = BinanceKit.parseBalancesToAccountAssetMap(accountInfoRst.balances)
  156. }
  157. const onTickFun = async function() {
  158. const task = this
  159. const context = task.context
  160. // 搜集所有价格数据
  161. await priceHandler(context, task)
  162. // 获取账户数据
  163. await accountHandler(context, task)
  164. // 展示关键信息
  165. showInfo(context, task)
  166. // 交易、订单处理
  167. await orderHandler(context, task)
  168. }
  169. const onePro = new OneTask('OnePro', PrivateConfig.delay, OneTask.baseInit, onTickFun)
  170. onePro.Start()