SHARE
TWEET

Untitled

a guest Feb 14th, 2020 119 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
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top