Closed L-S-Ross closed 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? :)
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)) }
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.
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.
@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
.
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.
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?
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...
@ddeath @f3rno
@L-S-Ross what exactly are you trying to do?
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?
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?
I always forget to add @f3rno
@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:
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?
@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.
@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?
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; `
@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.
@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?
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 ] ] ]