Guest User

Untitled

a guest
Feb 14th, 2020
178
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2. * Bitmex抢单对冲策略
  3. */
  4. global.Promise = require('bluebird');
  5. require('../logger')
  6.  
  7. import { FtxWs, FtxClient, FtxSubscriber } from '../ftx'
  8. import { BitmexClient, BitmexSubscriber } from '../bitmex'
  9. import utils from '../common/utils'
  10. const uuidv1 = require('uuid/v1');
  11.  
  12. const SYMBOL = 'XBTUSD'
  13. const FTX_CLIENT_ID = 'bitmexTaker'
  14. // const ASK_ORDER_TRIGER_SIZE = 8765 //卖单触发的size
  15.  
  16. const config = require('config').ftxFrontrun
  17. const bitmex = new BitmexClient(config.bitmex)
  18. const bitmexSub = new BitmexSubscriber({ bitmex, account: config.bitmex.account })
  19. const ftx = new FtxClient(config.ftx)
  20. const ftxWs = new FtxWs(config.ftx)
  21. const ftxSub = new FtxSubscriber({ ftxWs })
  22. var moment = require('moment');
  23.  
  24.  
  25. //scripts context
  26. const context = {
  27. ftxEffectiveSize: 30, //ftx 有效深度价格
  28. bitmexEffectiveSize: 100000, //bitmex 有效深度价格
  29. arbPercentage: 0.001,
  30. increasePositionSensitivity: 1.0,
  31. decreasePositionSensitivity: 0.5,
  32. orderSize: 1,
  33. threashold: 1,
  34. scriptStarted: false, //脚本是否启动
  35. bitmexAsk: null, //bitmex 卖1
  36. bitmexBid: null, //bitmex 买1
  37. ftxBid: null, //ftx 买1
  38. ftxAsk: null, //ftx 卖1
  39. takerProcessOngoing: false, //taker流程过滤执行
  40. apiCount: 0,
  41. buyInterestAdjust: 0,
  42. sellInterestAdjust: 0,
  43. ftxPosition: null,
  44. unrealizedPnl: null,
  45. currentFTXUSDbalance: null,
  46. currentFTXBTCbalance: null,
  47. ftxBTCBalance: null,
  48. currentFTXETHbalance: null
  49. }
  50.  
  51. //---------------- script init ------------------
  52.  
  53. context.scriptStarted = true
  54.  
  55. process.on('SIGINT', async () => {
  56. context.scriptStarted = false
  57. await ftxWs.terminate()
  58. process.exit(0)
  59. })
  60.  
  61. bitmex.on('error', console.error)
  62.  
  63. getInterestRate();
  64. getBalanceFTX();
  65.  
  66. bitmexSub.subscribeOrderbook10(SYMBOL, (bids, asks, timestamp) => {
  67. try {
  68. var bitmexBidCount = 0;
  69. var BitmexAskCount = 0;
  70. for (var i = 0; i < bids.length; i++) {
  71. bitmexBidCount += bids[i].size;
  72. if (bitmexBidCount >= context.bitmexEffectiveSize) {
  73. context.bitmexBid = bids[i].price;
  74. break;
  75. }
  76. else if (i == bids.length && bitmexBidCount < context.bitmexEffectiveSize) {
  77. context.bitmexBid = null;
  78. }
  79. }
  80. for (var i = 0; i < asks.length; i++) {
  81. BitmexAskCount += asks[i].size;
  82. if (BitmexAskCount >= context.bitmexEffectiveSize) {
  83. context.bitmexAsk = asks[i].price;
  84. break;
  85. }
  86. else if (i == asks.length && BitmexAskCount < context.bitmexEffectiveSize) {
  87. context.bitmexAsk = null;
  88. }
  89. }
  90. takerCheck();
  91. } catch (err) {
  92. console.error(err)
  93. }
  94. })
  95.  
  96.  
  97.  
  98. //订阅用户bitmex position
  99. bitmexSub.subscribePosition(SYMBOL, (position, action) => {
  100. try {
  101. context.openQty = parseFloat(position.currentQty);
  102. } catch (err) {
  103. console.error(err)
  104. }
  105. })
  106.  
  107. //订阅用户bitmex margin
  108. bitmexSub.subscribeMargin((margin) => {
  109. try {
  110. context.nowMarginBalance = parseFloat(margin.marginBalance) / 1e8;
  111. } catch (err) {
  112. console.error(err)
  113. }
  114. })
  115.  
  116.  
  117. ftxWs.connect().then(rsp => {
  118. //订阅 ftx orderbook
  119. ftxSub.subscribeOrderbook('BTC-PERP', (orderbook, data) => {
  120. try {
  121. var ftxBidCount = 0;
  122. var ftxAskCount = 0;
  123. for (var i = 0; i < orderbook.bids.length; i++) {
  124. ftxBidCount = ftxBidCount + orderbook.bids[i][1];
  125. if (ftxBidCount >= context.ftxEffectiveSize) {
  126. context.ftxBid = orderbook.bids[i][0];
  127. break;
  128. }
  129. else if (i == orderbook.bids.length && ftxBidCount < context.ftxEffectiveSize) {
  130. context.ftxBid = null;
  131. }
  132. }
  133. for (var i = 0; i < orderbook.asks.length; i++) {
  134. ftxAskCount = ftxAskCount + orderbook.asks[i][1];
  135. if (ftxAskCount >= context.ftxEffectiveSize) {
  136. context.ftxAsk = orderbook.asks[i][0];
  137. break;
  138. }
  139. else if (i == orderbook.asks.length && ftxAskCount < context.ftxEffectiveSize) {
  140. context.ftxAsk = null;
  141. }
  142. }
  143. takerCheck();
  144. } catch (err) {
  145. console.error(err)
  146. }
  147.  
  148. })
  149.  
  150. }).catch(err => {
  151. console.error('connect FTX websocket failed.', err.message)
  152. process.exit(0)
  153. })
  154.  
  155. //-------------- end script init -----------------
  156.  
  157. //-------------- script methods ------------------
  158.  
  159.  
  160. async function takerCheck() {
  161. if (context.takerProcessOngoing) {
  162. return
  163. }
  164. context.takerProcessOngoing = true;
  165. if (context.bitmexAsk != null && context.ftxAsk != null && context.bitmexBid != null && context.ftxBid != null && context.ftxPosition != null && context.currentFTXUSDbalance!=null && context.currentFTXBTCbalance!=null && context.ftxBTCBalance!=null && context.currentFTXETHbalance != null) {
  166. var sendOrderSize = parseFloat((context.orderSize * context.ftxBTCBalance).toFixed(4));
  167. var btcThreashold = context.threashold * context.ftxBTCBalance;
  168. var buyArb = null;
  169. var sellArb = null;
  170. for (var i = 0; i < 5; i++) {
  171. if (Math.abs(context.ftxPosition) < btcThreashold * (i + 1)) {
  172. if (context.ftxPosition < 0) {
  173. buyArb = context.arbPercentage - context.arbPercentage * context.decreasePositionSensitivity * i + context.buyInterestAdjust;
  174. sellArb = context.arbPercentage + context.arbPercentage * context.increasePositionSensitivity * i + context.sellInterestAdjust;
  175. }
  176. else if (context.ftxPosition > 0) {
  177. buyArb = context.arbPercentage + context.arbPercentage * context.increasePositionSensitivity * i + context.buyInterestAdjust;
  178. sellArb = context.arbPercentage - context.arbPercentage * context.decreasePositionSensitivity * i + context.sellInterestAdjust;
  179. }
  180. break;
  181. }
  182. else if (Math.abs(context.ftxPosition) > btcThreashold * (5) && Math.abs(context.ftxPosition) < btcThreashold * 6) {
  183. if (context.ftxPosition < 0) {
  184. buyArb = context.arbPercentage - context.arbPercentage * context.decreasePositionSensitivity * 5 + context.buyInterestAdjust;
  185. sellArb = context.arbPercentage + context.arbPercentage * context.increasePositionSensitivity * 6 + context.sellInterestAdjust;
  186. }
  187. if (context.ftxPosition > 0) {
  188. buyArb = context.arbPercentage + context.arbPercentage * context.increasePositionSensitivity * 6 + context.buyInterestAdjust;
  189. sellArb = context.arbPercentage - context.arbPercentage * context.decreasePositionSensitivity * 5 + context.sellInterestAdjust;
  190. }
  191. break;
  192. }
  193. else if (Math.abs(context.ftxPosition) >= btcThreashold * (6)) {
  194. if (context.ftxPosition < 0) {
  195. buyArb = context.arbPercentage - context.arbPercentage * context.decreasePositionSensitivity * 6 + context.buyInterestAdjust;
  196. sellArb = null;
  197. }
  198. if (context.ftxPosition > 0) {
  199. buyArb = null;
  200. sellArb = context.arbPercentage - context.arbPercentage * context.decreasePositionSensitivity * 6 + context.sellInterestAdjust;
  201. }
  202. break;
  203. }
  204. }
  205. var clientID = uuidv1();
  206. let tasks = []
  207.  
  208. if (context.bitmexAsk < context.ftxBid / (1 + buyArb) && buyArb != null) {
  209. const task = new Promise((resolve, reject) => {
  210. Promise.all([
  211. sendOrderFTX('BTC-PERP', "sell", context.ftxAsk - 7, sendOrderSize, 'limit', false, false, true)
  212. ]).then(() => {
  213. resolve()
  214. }).catch(err => { reject(err) });
  215. })
  216. tasks.push(task)
  217. }
  218.  
  219. if (context.bitmexBid > context.ftxAsk * (1 + sellArb) && sellArb != null) {
  220. const task = new Promise((resolve, reject) => {
  221. Promise.all([
  222. sendOrderFTX('BTC-PERP', "buy", context.ftxBid + 7, sendOrderSize, 'limit', false, false, true)
  223. ]).then(() => {
  224. resolve()
  225. }).catch(err => { reject(err) });
  226. })
  227. tasks.push(task)
  228. }
  229.  
  230. if (tasks.length > 0) {
  231. await Promise.all(tasks)
  232. }
  233. await utils.sleep(5000);
  234. }
  235. context.takerProcessOngoing = false;
  236. }
  237.  
  238. async function sendOrderFTX(future, side, price, size, type, reduceOnly, postOnly, ioc) {
  239. try {
  240. const resp = await ftx._post('/orders', {
  241. market: future,
  242. side,
  243. price,
  244. size,
  245. 'order_type': type,
  246. reduceOnly,
  247. postOnly,
  248. ioc,
  249. clientId: `${FTX_CLIENT_ID}-${uuidv1()}`
  250. });
  251. console.log(resp);
  252. } catch (err) {
  253. console.error(err);
  254. }
  255. }
  256.  
  257. async function getInterestRate() {
  258. try {
  259. var bitmexCurrentInterest = 0;
  260. var bitmexNextInterest = 0;
  261. var ftxFunding = 0;
  262. var timetoBitmexFunding = 0;
  263. var adjustedbitmexFunding = 0;
  264. context.apiCount = context.apiCount + 1;
  265. const result = await bitmex.request('GET', 'instrument/active');
  266. for (var i = 0; i < result.length; i++) {
  267. if (result[i].symbol == 'XBTUSD') {
  268. timetoBitmexFunding = moment(result[i].fundingTimestamp).unix() - moment(moment().valueOf()).unix();
  269. bitmexCurrentInterest = result[i].fundingRate / 8;
  270. bitmexNextInterest = result[i].indicativeFundingRate;
  271. }
  272. }
  273. const resp = await ftx.getFutureStats('BTC-PERP');
  274. ftxFunding = resp.nextFundingRate;
  275. var tempBuyInterest = 0;
  276. var tempSellInterest = 0;
  277. if (timetoBitmexFunding < 1800) {
  278. adjustedbitmexFunding = bitmexCurrentInterest * 8;
  279. } else if (timetoBitmexFunding < 3600) {
  280. adjustedbitmexFunding = bitmexCurrentInterest * 4;
  281. } else if (timetoBitmexFunding < 7200) {
  282. adjustedbitmexFunding = bitmexCurrentInterest * 2;
  283. } else {
  284. adjustedbitmexFunding = bitmexCurrentInterest;
  285. }
  286.  
  287. if (ftxFunding < 0) {
  288. tempBuyInterest = tempBuyInterest + ftxFunding * 2.5;
  289. tempSellInterest = tempSellInterest - ftxFunding * 2.5;
  290. }
  291. if (ftxFunding >= 0) {
  292. tempBuyInterest = tempBuyInterest + ftxFunding * 2.5;
  293. tempSellInterest = tempSellInterest - ftxFunding * 2.5;
  294. }
  295. if (adjustedbitmexFunding < 0) {
  296. tempBuyInterest = tempBuyInterest + adjustedbitmexFunding;
  297. tempSellInterest = tempSellInterest - adjustedbitmexFunding;
  298. }
  299. if (adjustedbitmexFunding >= 0) {
  300. tempBuyInterest = tempBuyInterest + adjustedbitmexFunding;
  301. tempSellInterest = tempSellInterest - adjustedbitmexFunding;
  302. }
  303. context.buyInterestAdjust = tempBuyInterest;
  304. context.sellInterestAdjust = tempSellInterest;
  305. } catch (err) {
  306. context.apiCount = context.apiCount + 1;
  307. context.buyInterestAdjust = 0;
  308. context.sellInterestAdjust = 0;
  309. console.log(err);
  310. }
  311. }
  312.  
  313. async function getPositions() {
  314. const data = await ftx.getPositions();
  315. try {
  316. for (var i = 0; i < data.length; i++) {
  317. if (data[i].future == "BTC-PERP") {
  318. context.ftxPosition = parseFloat(data[i].netSize);
  319. context.unrealizedPnl = parseFloat(data[i].unrealizedPnl);
  320. }
  321. }
  322. } catch (err) {
  323. console.log(err);
  324. }
  325. }
  326.  
  327. async function getBalanceFTX() {
  328. const data = await ftx.getBalances();
  329.  
  330. try {
  331. for (var i = 0; i < data.length; i++) {
  332. if (data[i].coin == 'USD') {
  333. context.currentFTXUSDbalance = data[i].total + context.unrealizedPnl;
  334. }
  335. if (data[i].coin == 'BTC') {
  336. context.currentFTXBTCbalance = data[i].total;
  337. }
  338. if (data[i].coin == 'ETH') {
  339. context.currentFTXETHbalance = data[i].total;
  340. }
  341. }
  342. if(context.currentFTXUSDbalance == null)
  343. {
  344. context.currentFTXUSDbalance = 0;
  345. }
  346. if(context.currentFTXBTCbalance == null)
  347. {
  348. context.currentFTXBTCbalance = 0;
  349. }
  350. if(context.currentFTXETHbalance == null)
  351. {
  352. context.currentFTXETHbalance = 0;
  353. }
  354. context.ftxBTCBalance = context.currentFTXUSDbalance * context.ftxBid + context.currentFTXBTCbalance + context.currentFTXETHbalance*280;
  355. } catch (err) {
  356. console.log(err);
  357. }
  358. }
  359.  
  360.  
  361. setInterval(() => {
  362. getInterestRate();
  363. }, 20000);
  364.  
  365. setInterval(() => {
  366. getPositions();
  367. getBalanceFTX();
  368. }, 3000);
RAW Paste Data