bitfinexcom / bitfinex-api-node

BITFINEX NodeJS trading API - Bitcoin, Litecoin, and Ether exchange
https://www.bitfinex.com/
MIT License
462 stars 213 forks source link

After parse, how do you get the specific info/values from the JSON string? #303

Closed L-S-Ross closed 6 years ago

L-S-Ross commented 6 years ago

The [0, 'ws' [[key, key[value]]]] is confusing to a newbie, I can do data.subdata and data[n] location but cant get into the following array and extract just the data i want. I don't understand why. Can anybody actually help me do that? And not just send me to another page that doesn't explain how to use the code on that page.

[ 0, 'ws', [ [ 'exchange', 'BTC', 0, 0, null ], [ 'exchange', 'USD', 0, 0, null ], [ 'margin', 'XRP', -0.00003809, 0, null ], [ 'exchange', 'ETH', 0.07997982, 0, null ], [ 'margin', 'BTC', 0.01610578, 0, null ], [ 'margin', 'ETH', 0.1043368, 0, null ], [ 'margin', 'GBP', 2.04437386, 0, null ], [ 'margin', 'USD', 75.58465857, 0, null ], [ 'margin', 'IOT', 0, 0, null ] ] ]

f3rno commented 6 years ago

@L-S-Ross the ws packet represents a wallet snapshot, and the individual entries are the state of your wallets. The data structure is documented here: https://docs.bitfinex.com/v2/reference#ws-auth-wallets

You can pass the individual wallet data arrays ([ 'margin', 'USD', 75.58465857, 0, null ]) to the Wallet model if you want key/value access. Then you can do wallet.balance, etc. An example (untested):

const { Wallet } = require('bitfinex-api-node/lib/models')

const w = new Wallet(['margin', 'USD', 75.58465857, 0, null])
console.log('USD margin balance: %f', w.balance)

// this also works
const wallets = Wallet.unserialize([
  [ 'exchange', 'BTC', 0, 0, null ],
  [ 'exchange', 'USD', 0, 0, null ],
  [ 'margin', 'XRP', -0.00003809, 0, null ],
  [ 'exchange', 'ETH', 0.07997982, 0, null ],
  [ 'margin', 'BTC', 0.01610578, 0, null ],
  [ 'margin', 'ETH', 0.1043368, 0, null ],
  [ 'margin', 'GBP', 2.04437386, 0, null ],
  [ 'margin', 'USD', 75.58465857, 0, null ],
  [ 'margin', 'IOT', 0, 0, null ]
])

console.log('BTC exchange balance: %f', wallets[0].balance)

Passsing transform: true to the WSv2 client options (where you also provide apiKey & apiSecret) will cause it to return models instead of raw arrays where possible. Then you don't need to convert to a Wallet model yourself.

Does that help? :)

L-S-Ross commented 6 years ago

Thanks f3rno, where do I pass transform: true? Somewhere in here right?

wss.onopen = () => { // API keys setup here (See "Authenticated Channels") const crypto = require('crypto-js') const apiKey = 'The Api key' const apiSecret = 'The Api shhh' const authNonce = Date.now() * 1000 const authPayload = 'AUTH' + authNonce const authSig = crypto .HmacSHA384(authPayload, apiSecret) .toString(crypto.enc.Hex)

const payload = {
      apiKey,
      authSig,
      authNonce,
      authPayload,
      event: 'auth', 
      // ... 
      filter: [
        'trading', // orders, positions, trades 
        'funding', // offers, credits, loans, funding trades
        'wallet',  // wallet 
        'algo',    // algorithmic orders
        'balance', // balance (tradable balance, ...)
        'notify'   // notifications
      ]
}

wss.send(JSON.stringify(payload)) }

ddeath commented 6 years ago
import * as BFX from 'bitfinex-api-node';

const bfx = new BFX({
      apiKey: 'YOUR_API_KEY_HERE',
      apiSecret:  'YOUR_API_SECRET_HERE',

      ws: {
        autoReconnect: true,
        packetWDDelay: 10 * 1000,
        transform: true,
      },
    });

const webSocket = bfx.ws(2);

webSocket.open().then(() => {
  webSocket.auth();
});

Also maybe take a look at README.md and examples in thes repository.

L-S-Ross commented 6 years ago

This is not the same as the example I saw in there, by f3rno...

'use strict'

require('dotenv').config()

const BFX = require('../')
const SocksProxyAgent = require('socks-proxy-agent')

const { API_KEY, API_SECRET, REST_URL, WS_URL, SOCKS_PROXY_URL } = process.env
const agent = SOCKS_PROXY_URL ? new SocksProxyAgent(SOCKS_PROXY_URL) : null

const bfx = new BFX({
  apiKey: API_KEY,
  apiSecret: API_SECRET,

  ws: {
    url: WS_URL,
    agent
  },

  rest: {
    url: REST_URL,
    agent
  }
})

module.exports = bfx

It's easy to say go to the read me but the read me is written for people who know programming, it doesn't explain what the code is doing, so when I copy and paste and it doesn't work, I ask what to do and someone says go back to the page that didn't explain it in the first place and start there again. I get nowhere and experienced programmers get a laugh, then they get pissed I'm asking the same question again. ddeath, did you tell me where i needed to enter my APIkey? nope. you asked where i put it, but on the exxample page it doesnt say where it should go, so how would i know I need to enter it? then you say go back to the page. ughh.

ddeath commented 6 years ago

@L-S-Ross you were asking where to pass transform: true so I posted an example for you where it should go.

Also, nobody is laughing at you. I suggested you go through examples because there are examples which use transform: true.

L-S-Ross commented 6 years ago

I'm sorry, I've built a decent bot over 2 weeks and I've spent 3 days now just trying to get access to the balance, for a position size calculation and i'm getting nowhere. I dont mean to be rude, I'm frustrated. thanks ddeath, again.

L-S-Ross commented 6 years ago

So is the way models work, like... I can create a const = to a model from the bfxx lib, then pass data into that model, like a candle, a wallet etc... then I can iterate through the model with model.data and model[1], to capture data and use it elsewhere?

L-S-Ross commented 6 years ago

f3rno... thanks, I'm getting the value after USD in my console message, not the real balance. I changed that string to the values I want and got undefined, I changed that to the snapshopt object and got nothing at all. I think I may not be following wht you are telling me to do. I dont think you mean for me to just copy and paste. I don't know Node.js very well, I know swift a little more, so I may need my hand holding like a little boy here. But if i gget it, I can copy it for all the other messages I need to transfer into objects. Please advise...

L-S-Ross commented 6 years ago

@ddeath @f3rno

f3rno commented 6 years ago

@L-S-Ross what exactly are you trying to do?

L-S-Ross commented 6 years ago

I started from scratch again and it’s working well... thanks. I just get an error when I run the ticker now. Cannot read[0] of undefined. In the ws2 file. I made an issue. Was that the right thing to do?

L-S-Ross commented 6 years ago

I want to be able to take a specific wallet balance and use that number in a calculation to set my order sizes... I dont see a way for that mapped out on here, could you point me in the right direction please?

L-S-Ross commented 6 years ago

I always forget to add @f3rno

f3rno commented 6 years ago

@L-S-Ross have a look here: https://github.com/bitfinexcom/bitfinex-api-node/blob/master/lib/transports/rest2.js#L364

You can use the REST api to fetch your wallets/balances, and then do what you want with them. There is also an example which will get merged in here, but it does a lot more than just the fetch (I've highlighted the line).

Or, you can use the recommended approach (slightly more complicated) and listen for wallet snapshots/updates. For that, look here: https://github.com/bitfinexcom/bitfinex-api-node/blob/master/lib/transports/ws2.js#L1921

I will update the wiki with documentation & tutorials for the v2 APIs soon, until then I hope this helps :shipit:

L-S-Ross commented 6 years ago

Thanks, I think the websocket way is better for me, to update automatically when i make a new trade. I copied the ws2 and made - ws.onWalletSnapshot({}, (wallets) => { debug(`Wallet snapshot: ${JSON.stringify(wallets, null, 2)}

it shows all wallets, but how would I get just my BTC wallet? I would need to copy that line above and have another for onWalletUpdate, right?

f3rno commented 6 years ago

@L-S-Ross you'll need to parse it from the snapshot response :) The wallet updates are sent out when a balance changes, the snapshots after connecting to the ws v2 API.

L-S-Ross commented 6 years ago

@f3rno I did this - ws.onWalletSnapshot({}, (wallets) => {

console.log('this right here ', JSON.parse(wallets, null, 2)) })

I got - [object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object] ^

SyntaxError: Unexpected token o in JSON at position 1

What did I do wrong?

L-S-Ross commented 6 years ago

Hi @f3rno, I have an issue with ws.open. If i dont call it twice, I don't get candles data, but all other data comes. I can't understand it. If you have time (You've helped me a lot this week already and it is the weekend so i don't expect anything), could you check my code and tell me what I've done wrong please?

` const request = require('request'); const bfx = require('./bfx') const ws = bfx.ws(2) var prices = {};

function BfxTrade(pairs){ this.initAmount = 100; this.reserve={}; this.prices={}; this.orderChecks = {}; };

BfxTrade.prototype.signIn = function(){ 'use strict' process.env.DEBUG = 'bfx:examples:*' const debug = require('debug')('bfx:examples:ws2_auth')

ws.on('open', () => { // wait for socket open ws.auth() // & authenticate debug('open') }) ws.on('error', (err) => { debug('error: %j', err) }) ws.once('auth', () => { debug('authenticated') // do something with authenticated ws stream }) // Register a callback for wallets snapshot that comes in (account orders) ws.onWalletSnapshot({}, (wallets) => {

console.log(Wallet snapshot: ${JSON.stringify(wallets, null, 2)}) })

ws.onWalletUpdate({}, (wallets) => { console.log(Wallet snapshot: ${JSON.stringify(wallets, null, 2)}) }) // Open the websocket connection ws.open() }

BfxTrade.prototype.getBalance = function(pair, callback){

}

BfxTrade.prototype.getPrices = function(){ var self = this; 'use strict'

process.env.DEBUG = 'bfx:examples:*'

const debug = require('debug')('bfx:examples:ws2_tickers') const bfx = require('./bfx')

const SYMBOL = 'tETHBTC' const ws = bfx.ws(2)

ws.on('open', () => { console.log('open') ws.subscribeTicker(SYMBOL) })

ws.onTicker({ symbol: SYMBOL }, (ticker) => { console.log('%s ticker: %j', SYMBOL, ticker) if(!self.prices.hasOwnProperty(pair)){ self.prices[pair] = {lastPrice: - Infinity, dayHighPrice: - Infinity, dayLowPrice: Infinity, askPrice: - Infinity, bidPrice: Infinity, volume: - Infinity, dayChange: - Infinity, dayChangePct: - Infinity } };

    self.prices[pair]['lastPrice'] = ticker['lastPrice'];
    self.prices[pair]['bidPrice'] = ticker['bid'];
    self.prices[pair]['askPrice'] = ticker['ask'];
    self.prices[pair]['dayHighPrice'] = ticker['high'];
    self.prices[pair]['dayLowPrice'] = ticker['low'];
    self.prices[pair]['volume'] = ticker['volume'];
    self.prices[pair]['dayChange'] = ticker['dailyChange'];
    self.prices[pair]['dayChangePct'] = ticker['dailyChangePerc'];

    console.log('ticker prices ', self.prices);

})

// ws.open() }

BfxTrade.prototype.resetPrices = function(pair){ // this.prices[pair]['highPrice'] = -Infinity; // this.prices[pair]['lowPrice'] = Infinity; }

BfxTrade.prototype.testTrade = function(pair, price, amount, type, action, callback){

switch(type){
    case "buy":
        if(action == "long"){
            this.initAmount-=1.002*amount*price;

        }else{
            this.initAmount+=0.998*(2*this.reserve[pair]-amount*price);
        }

        return callback();
    case "sell":
        if(action == "long"){
            this.initAmount+=0.998*amount*price;

        }else{
            this.reserve[pair] = amount*price;
            this.initAmount-=1.002*this.reserve[pair];
        }

        return callback();
}

};

BfxTrade.prototype.getHistData = function(pair, callback){ var self = this; 'use strict'

const debug = require('debug')('bfx:examples:ws2_candles') const bfx = require('./bfx') const ws = bfx.ws(2, { manageCandles: true, // enable candle dataset persistence/management transform: true // converts ws data arrays to Candle models (and others) })

const CANDLE_KEY = 'trade:1m:tETHUSD' ws.on('open', () => { console.log('open') ws.subscribeCandles(CANDLE_KEY) })

let prevTS = null // 'candles' here is an array ws.onCandle({ key: CANDLE_KEY }, (candles) => { if (prevTS === null || candles[0].mts > prevTS) { const c = candles[1] // report previous candle debug(%s %s open: %f, high: %f, low: %f, close: %f, volume: %f, CANDLE_KEY, new Date(c.mts).toLocaleTimeString(), c.open, c.high, c.low, c.close, c.volume, // console.log(candles) ) prevTS = candles[0].mts if(!self.prices.hasOwnProperty(pair)){ self.prices[pair] = {open: - Infinity, high: - Infinity, low: Infinity, close: - Infinity } };

    self.prices[pair]['open'] = c['open'];
    self.prices[pair]['high'] = c['high'];
    self.prices[pair]['low'] = c['low'];
    self.prices[pair]['close'] = c['close'];

    console.log('candle prices ', self.prices); 

}

})

ws.open()

}

BfxTrade.prototype.trade = function(pair, price, amount, action, side, callback){ // var self = this; // console.log(pair, 'Placing your order'); // rest.new_order(pair, amount.toString(), price.toString(), 'bitfinex', side, 'limit', function(err, data){ // if(!err){ // console.log(pair, ' Order was placed successfully, price ', price, ' amount ', amount, ' id ', data['id']); // setTimeout(function(){ // checkOrder(self, pair, data['id'], action, function(success){ // return callback(success); // }) // }, 2000) // }else { // console.log('trade error ', err.toString()); // return callback(false); // } // });

}

function checkOrder(self, pair, orderId, action, callback){ process.env.DEBUG = 'bfx:examples:*'

const debug = require('debug')('bfx:examples:ws2_auth') const bfx = require('./bfx') const ws = bfx.ws(2)

ws.on('open', () => { // wait for socket open ws.auth() // & authenticate

console.log('open') })

ws.on('error', (err) => { console.log('error: %j', err) console.log('') })

ws.once('auth', () => { console.log('authenticated')

// do something with authenticated ws stream })

// Register a callback for any order snapshot that comes in (account orders) ws.onOrderSnapshot({}, (orders) => { console.log(order snapshot: ${JSON.stringify(orders, null, 2)}) })

// Open the websocket connection // ws.open() }

function cancelOrder(pair, orderId, callback){ rest.cancel_order(orderId, function(err, data){ if(!err){ console.log(pair, 'Order has been cancelled', orderId); return callback(); }else { console.log(pair, 'error occured when cancelling order', orderId); console.log(err.toString()); setTimeout(function(){ cancelOrder(pair, orderId, callback) }, 1000);

    }
})

}

module.exports = BfxTrade; `

L-S-Ross commented 6 years ago

@f3rno Hey buddy, I worked it out. I only open ws once and get all the info, I even worked out how to get each individual wallet's balance as a separate variable. Thanks for all your help.

L-S-Ross commented 6 years ago

@f3rno Spoke too soon. I didnt change anything but suddenly I get this error about the tick.js file

/home/leon/Projects/testbot/node_modules/bitfinex-api-node/lib/models/tick.js:44 if (Array.isArray(arr[0])) { ^

TypeError: Cannot read property '0' of undefined

any ideas?