Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/ws2 new funding functions #543

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
4.0.15
- WSv2: submitFundingOffer function
- WSv2: cancelFundingOffer function
- WSv2: closeFundingLoan function
- WSv2: closeFundingCredit function

4.0.14
- fix: README docs reference

Expand Down
4 changes: 2 additions & 2 deletions docs/WS2Manager.html

Large diffs are not rendered by default.

3,898 changes: 2,671 additions & 1,227 deletions docs/WSv2.html

Large diffs are not rendered by default.

240 changes: 238 additions & 2 deletions docs/global.html

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions docs/index.html

Large diffs are not rendered by default.

174 changes: 163 additions & 11 deletions docs/transports_ws2.js.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/util_precision.js.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/util_ws2.js.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/ws2_manager.js.html

Large diffs are not rendered by default.

154 changes: 154 additions & 0 deletions lib/transports/ws2.js
Original file line number Diff line number Diff line change
Expand Up @@ -1931,6 +1931,160 @@ class WSv2 extends EventEmitter {
return this._getEventPromise(`order-new-${packet.cid}`)
}

/**
* @typedef {object} FundingOffer
* @property {string} type - offer type i.e. LIMIT, FRRDELTAVAR
* @property {string} symbol - symbol i.e. fUSD, fBTC
* @property {string} amount - positive for buy, negative for sell i.e. '50'
* @property {string} rate - rate of the offer
* @property {number} period - Time period of offer. Min:2, Max:30 days
* @property {number} flags - flags
*/

/**
* Sends a new funding offer to the server. Emits an error if not
* authenticated. The funding offer can be either key/value pair object
* literal, an instance of FundingOffer class or an array
*
* @see WSv2#cancelFundingOffer
* @see WSv2#closeFundingCredit
* @see WSv2#closeFundingLoan
*
* @param {FundingOffer|Array} payload - funding offer object model or array
* @throws an error if not authenticated
* @example
* const fo = new FundingOffer({
* type: 'LIMIT',
* symbol: 'fUSD',
* amount: '50',
* rate: '0.001',
* period: 2,
* flags: 0
* }, ws)
*
* ws.submitFundingOffer(fo)
*
* ws.onFundingOfferNew({ symbol: 'fUSD' }, (resp) => {
* console.log('Funding offer status: ', resp.status)
* })
*/
async submitFundingOffer (payload) {
if (!this._isAuthenticated) {
throw new Error('not authenticated')
}

const packet = (
payload instanceof FundingOffer
? payload
: new FundingOffer(payload)
).toNewOfferPacket()

if (this._affCode) {
packet.meta.aff_code = packet.meta.aff_code || this._affCode
}

this.send([0, 'fon', null, packet])
}

/**
* Cancels funding offer by ID. Emits an error if not authenticated.
* The ID can be passed as a number, key/value pair object literal,
* an instance of FundingOffer class or an array
*
* @see WSv2#submitFundingOffer
* @see WSv2#closeFundingCredit
* @see WSv2#closeFundingLoan
*
* @param {FundingOffer|object|Array|number} payload - funding offer model,
* array or ID to cancel
* @throws an error if not authenticated
* @example
* ws.cancelFundingOffer({ id: 1234 })
*
* ws.onFundingOfferClose({ symbol: 'fUSD' }, (resp) => {
* console.log('Funding offer status: ', resp.status)
* })
*/
cancelFundingOffer (payload) {
if (!this._isAuthenticated) {
throw new Error('not authenticated')
}

const id = _isNumber(payload)
? payload
: Array.isArray(payload)
? payload[0]
: payload.id

this.send([0, 'foc', null, { id }])
}

/**
* Cancels funding loan by ID. Emits an error if not authenticated.
* The ID can be passed as a number, key/value pair object literal,
* an instance of FundingLoan class or an array
*
* @see WSv2#submitFundingOffer
* @see WSv2#cancelFundingOffer
* @see WSv2#closeFundingCredit
*
* @param {FundingLoan|object|Array|number} payload - funding loan class,
* object literal, array or ID to cancel
* @throws an error if not authenticated
* @example
* ws.closeFundingLoan({ id: 1234 })
*
* ws.onFundingLoanClose({ symbol: 'fUSD' }, (resp) => {
* console.log('Funding loan status: ', resp.status)
* })
*/
closeFundingLoan (payload) {
if (!this._isAuthenticated) {
throw new Error('not authenticated')
}

const id = _isNumber(payload)
? payload
: Array.isArray(payload)
? payload[0]
: payload.id

this.send([0, 'flc', null, { id }])
}

/**
* Cancels funding credit by ID. Emits an error if not authenticated.
* The ID can be passed as a number, key/value pair object literal,
* an instance of FundingCredit class or an array
*
* @see WSv2#submitFundingOffer
* @see WSv2#cancelFundingOffer
* @see WSv2#closeFundingLoan
*
* @param {FundingCredit|object|Array|number} payload - funding credit class,
* object literal, array or ID to cancel
* @throws an error if not authenticated
* @example
* ws.closeFundingCredit({ id: 1234 })
*
* ws.onFundingCreditClose({ symbol: 'fUSD' }, (resp) => {
* console.log('Funding credit status: ', resp.status)
* })
*/
closeFundingCredit (payload) {
if (!this._isAuthenticated) {
throw new Error('not authenticated')
}

const id = _isNumber(payload)
? payload
: Array.isArray(payload)
? payload[0]
: payload.id

this.send([0, 'fcc', null, { id }])
}

/**
* Send a changeset to update an order in-place while maintaining position in
* the price queue. The changeset must contain the order ID, and supports a
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bitfinex-api-node",
"version": "4.0.14",
"version": "4.0.15",
"description": "Node reference library for Bitfinex API",
"engines": {
"node": ">=8.3.0"
Expand Down
204 changes: 203 additions & 1 deletion test/lib/transports/ws2-integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
const assert = require('assert')
const Promise = require('bluebird')
const WSv2 = require('../../../lib/transports/ws2')
const { Order } = require('bfx-api-node-models')
const { Order, FundingOffer } = require('bfx-api-node-models')
const { MockWSv2Server } = require('bfx-api-mock-srv')

const API_KEY = 'dummy'
Expand Down Expand Up @@ -224,6 +224,208 @@ describe('WSv2 integration', () => {
})
})

describe('submitFundingOffer', () => {
const testCases = {
'as class instance': {
payload: new FundingOffer({
type: 'LIMIT',
symbol: 'fUSD',
amount: '50',
rate: '0.001',
period: 2,
flags: 0
}),
expectedResult: {
type: 'LIMIT',
symbol: 'fUSD',
amount: '50.00000000',
rate: '0.00100000',
period: 2,
flags: 0
}
},
'as object literal': {
payload: {
type: 'LIMIT',
symbol: 'fUSD',
amount: '60',
rate: '0.003',
period: 7,
flags: 0
},
expectedResult: {
type: 'LIMIT',
symbol: 'fUSD',
amount: '60.00000000',
rate: '0.00300000',
period: 7,
flags: 0
}
},
'as array': {
payload: [
null, 'fUSD', null, null, '55', null, 'LIMIT', null, null, 0,
null, null, null, null, '0.002', 4
],
expectedResult: {
type: 'LIMIT',
symbol: 'fUSD',
amount: '55.00000000',
rate: '0.00200000',
period: 4,
flags: 0
}
}
}

Object.keys(testCases).forEach((scenario) => {
it(scenario, async () => {
let sentPackets = 0
wss = new MockWSv2Server()
ws = createTestWSv2Instance()

await ws.open()
await ws.auth()

ws._ws.send = (msgJSON) => {
const msg = JSON.parse(msgJSON)
assert.strictEqual(msg[1], 'fon')
assert.deepStrictEqual(msg[3], testCases[scenario].expectedResult)
sentPackets++
}

ws.submitFundingOffer(testCases[scenario].payload)
assert.strictEqual(sentPackets, 1)
})
})
})

describe('cancelFundingOffer', () => {
const testCases = {
'as class instance': {
payload: new FundingOffer({ id: 123 }),
expectedResult: { id: 123 }
},
'as object literal': {
payload: { id: 124 },
expectedResult: { id: 124 }
},
'as number': {
payload: 125,
expectedResult: { id: 125 }
},
'as array': {
payload: [126],
expectedResult: { id: 126 }
}
}

Object.keys(testCases).forEach((scenario) => {
it(scenario, async () => {
let sentPackets = 0
wss = new MockWSv2Server()
ws = createTestWSv2Instance()

await ws.open()
await ws.auth()

ws._ws.send = (msgJSON) => {
const msg = JSON.parse(msgJSON)
assert.strictEqual(msg[1], 'foc')
assert.deepStrictEqual(msg[3], testCases[scenario].expectedResult)
sentPackets++
}

ws.cancelFundingOffer(testCases[scenario].payload)
assert.strictEqual(sentPackets, 1)
})
})
})

describe('closeFundingLoan', () => {
const testCases = {
'as class instance': {
payload: new FundingOffer({ id: 123 }),
expectedResult: { id: 123 }
},
'as object literal': {
payload: { id: 124 },
expectedResult: { id: 124 }
},
'as number': {
payload: 125,
expectedResult: { id: 125 }
},
'as array': {
payload: [126],
expectedResult: { id: 126 }
}
}

Object.keys(testCases).forEach((scenario) => {
it(scenario, async () => {
let sentPackets = 0
wss = new MockWSv2Server()
ws = createTestWSv2Instance()

await ws.open()
await ws.auth()

ws._ws.send = (msgJSON) => {
const msg = JSON.parse(msgJSON)
assert.strictEqual(msg[1], 'flc')
assert.deepStrictEqual(msg[3], testCases[scenario].expectedResult)
sentPackets++
}

ws.closeFundingLoan(testCases[scenario].payload)
assert.strictEqual(sentPackets, 1)
})
})
})

describe('closeFundingCredit', () => {
const testCases = {
'as class instance': {
payload: new FundingOffer({ id: 123 }),
expectedResult: { id: 123 }
},
'as object literal': {
payload: { id: 124 },
expectedResult: { id: 124 }
},
'as number': {
payload: 125,
expectedResult: { id: 125 }
},
'as array': {
payload: [126],
expectedResult: { id: 126 }
}
}

Object.keys(testCases).forEach((scenario) => {
it(scenario, async () => {
let sentPackets = 0
wss = new MockWSv2Server()
ws = createTestWSv2Instance()

await ws.open()
await ws.auth()

ws._ws.send = (msgJSON) => {
const msg = JSON.parse(msgJSON)
assert.strictEqual(msg[1], 'fcc')
assert.deepStrictEqual(msg[3], testCases[scenario].expectedResult)
sentPackets++
}

ws.closeFundingCredit(testCases[scenario].payload)
assert.strictEqual(sentPackets, 1)
})
})
})

describe('listeners', () => {
it('manages listeners by cbGID', () => {
ws = createTestWSv2Instance()
Expand Down