Last active
February 26, 2023 23:51
-
-
Save snowkidind/9545ca43962dc1251a226031ea797b06 to your computer and use it in GitHub Desktop.
dydx nodejs typescript wrapper WIP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { DydxClient } = require('@dydxprotocol/v3-client') | |
const Web3 = require('web3') | |
const web31 = new Web3(process.env.RPC_NODE) | |
const web32 = new Web3(process.env.RPC_NODE) | |
const signer1 = web31.eth.accounts.wallet.add(process.env.TRADING_ZERO_PVT_KEY) | |
const signer2 = web32.eth.accounts.wallet.add(process.env.TRADING_ONE_PVT_KEY) | |
const { dateutils } = require('../utils') | |
const { iso8601, dateNowUTC, timeFmtDb } = dateutils | |
client1 = new DydxClient('https://api.dydx.exchange', { | |
web3: web31, | |
web3Provider: process.env.RPC_NODE | |
}) | |
client2 = new DydxClient('https://api.dydx.exchange', { | |
web3: web32, | |
web3Provider: process.env.RPC_NODE | |
}) | |
let inited = false | |
const init = async () => { | |
try { | |
const apiCreds1 = await client1.onboarding.recoverDefaultApiCredentials(signer1.address) | |
client1.apiKeyCredentials = apiCreds1 | |
const keyPairWithYCoordinate1 = await client1.onboarding.deriveStarkKey(signer1.address) | |
client1.starkPrivateKey = keyPairWithYCoordinate1.privateKey | |
const apiCreds2 = await client2.onboarding.recoverDefaultApiCredentials(signer2.address) | |
client2.apiKeyCredentials = apiCreds2 | |
const keyPairWithYCoordinate2 = await client2.onboarding.deriveStarkKey(signer2.address) | |
client2.starkPrivateKey = keyPairWithYCoordinate2.privateKey | |
inited = true | |
} catch (error) { | |
console.log(error) | |
console.log('WARNING: An error occurred initializing dydx client') | |
} | |
} | |
module.exports = { | |
getFills: async (market, createdBeforeOrAt, limit = 100, orderId = undefined, clientId = 1) => { | |
try { | |
if (!inited) await init() | |
let req = { | |
market: market, | |
limit: limit, | |
createdBeforeOrAt: createdBeforeOrAt, | |
} | |
if (typeof orderid !== 'undefined') { | |
req['orderId'] = orderId | |
} | |
if (clientId === 1) { | |
const resp = await client1.private.getFills(req) | |
return resp.fills | |
} else if (clientId === 2) { | |
const resp = await client2.private.getFills(req) | |
return resp.fills | |
} | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve fills') | |
} | |
}, | |
/* | |
Get an order by id from the active orderbook and order history | |
NOTE: a way to retrieve an unknown orderId is to poll for fills and then call for the exact orderId from the fill | |
*/ | |
getOrderById: async (orderId, clientId = 1) => { | |
try { | |
if (!inited) await init() | |
if (clientId === 1) { | |
const resp = await client1.private.getOrderById(orderId) | |
return resp.order | |
} else if (clientId === 2) { | |
const resp = await client2.private.getOrderById(orderId) | |
return resp.order | |
} | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve order') | |
} | |
}, | |
/* | |
Get active (not filled or canceled) orders for a user, stingey rate limit | |
*/ | |
getOrders: async (market, createdBeforeOrAt, limit = 100, clientId = 1) => { | |
try { | |
if (!inited) await init() | |
let req = { | |
market: market, | |
limit: limit, | |
createdBeforeOrAt: createdBeforeOrAt, | |
returnLatestOrders: true | |
} | |
if (clientId === 1) { | |
const orders = await client1.private.getOrders(req) | |
return orders.orders | |
} else if (clientId === 2) { | |
const orders = await client2.private.getOrders(req) | |
return orders.orders | |
} | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve orders') | |
} | |
}, | |
/* | |
Get active (not filled or canceled) orders for a user, relaxed rate limit | |
Bug: id is not optional, and should be | |
*/ | |
getActiveOrders: async (market, side, orderId, clientId = 1) => { | |
try { | |
if (!inited) await init() | |
if (clientId === 1) { | |
const resp = await client1.private.getActiveOrders(market, side, orderId) | |
return resp.orders | |
} else if (clientId === 2) { | |
const resp = await client2.private.getActiveOrders(market, side, orderId) | |
return resp.orders | |
} | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve orders') | |
} | |
}, | |
/* | |
contains price info for index and oracle | |
also contains future funding rate for market | |
*/ | |
getMarket: async (market) => { | |
try { | |
if (!inited) await init() | |
const orders = await client1.public.getMarkets(market) | |
return orders.markets[market] | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve market') | |
} | |
}, | |
getHistoricalPrices: async (market, resolution, fromISO, toISO, limit) => { | |
function translateCandle (resolution) { | |
let res | |
switch (resolution) { | |
case "1d": res = "1DAY"; break; | |
case "4h": res = "4HOURS"; break; | |
case "1h": res = "1HOUR"; break; | |
case "30m": res = "30MINS"; break; | |
case "15m": res = "15MINS"; break; | |
case "5m": res = "5MINS"; break; | |
case "1m": res = "1MIN"; break; | |
default: res = "1DAY" | |
} | |
return res | |
} | |
try { | |
if (!inited) await init() | |
const orders = await client1.public.getCandles({ market, resolution:translateCandle(resolution), fromISO, toISO, limit}) | |
return orders | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve historical prices') | |
} | |
}, | |
/* | |
gets funding rate for the past hours | |
*/ | |
getPastFundingRates: async (market, effectiveBeforeOrAt) => { | |
try { | |
if (!inited) await init() | |
const orders = await client1.public.getHistoricalFunding({ market, effectiveBeforeOrAt }) | |
return orders.historicalFunding | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve funding history') | |
} | |
}, | |
getFundingPayments: async (market, limit, effectiveBeforeOrAt, clientId = 1) => { | |
try { | |
if (!inited) await init() | |
if (clientId === 1) { | |
const payments = await client1.private.getFundingPayments({ market, limit, effectiveBeforeOrAt }) | |
return payments.fundingPayments | |
} else if (clientId === 2) { | |
const payments = await client2.private.getFundingPayments({ market, limit, effectiveBeforeOrAt }) | |
return payments.fundingPayments | |
} | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve funding payments') | |
} | |
}, | |
getHistoricalFunding: async (market, effectiveBeforeOrAt) => { | |
try { | |
if (!inited) await init() | |
const funding = await client1.public.getHistoricalFunding({ market, effectiveBeforeOrAt }) | |
return funding.historicalFunding | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve funding payments') | |
} | |
}, | |
getAccount: async(clientId = 1) => { | |
try { | |
if (!inited) await init() | |
if (clientId === 1) { | |
const account = (await client1.private.getAccount(signer1.address)).account | |
return account | |
} else if (clientId === 2) { | |
const account = (await client2.private.getAccount(signer2.address)).account | |
return account | |
} | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve account') | |
} | |
}, | |
getAccounts: async(clientId = 1) => { | |
try { | |
if (!inited) await init() | |
if (clientId === 1) { | |
const account = await client1.private.getAccounts() | |
if (account.accounts.length > 0) { | |
return account.accounts | |
} | |
} else if (clientId === 2) { | |
const account = await client2.private.getAccounts() | |
if (account.accounts.length > 0) { | |
return account.accounts | |
} | |
} | |
return [] | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve account') | |
} | |
}, | |
getPositions: async (market, status, limit, createdBeforeOrAt, clientId = 1) => { | |
try { | |
if (!inited) await init() | |
if (clientId === 1) { | |
const response = await client1.private.getPositions({ | |
market: market, | |
status: status, | |
limit: limit, | |
createdBeforeOrAt: createdBeforeOrAt, | |
}) | |
if (response.positions.length > 0) { | |
return response.positions | |
} | |
} else if (clientId === 2) { | |
const response = await client2.private.getPositions({ | |
market: market, | |
status: status, | |
limit: limit, | |
createdBeforeOrAt: createdBeforeOrAt, | |
}) | |
if (response.positions.length > 0) { | |
return response.positions | |
} | |
} | |
return [] | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve account') | |
} | |
}, | |
/** | |
*@description place a new order | |
* | |
* @market BTC-USD ETH-USD etc | |
* @side BUY SELL | |
* @type MARKET LIMIT STOP_LIMIT TRAILING_STOP TAKE_PROFIT | |
* @timeInForce GTT FOK IOC | |
* @postOnly true false | |
* @size | |
* @price | |
* @limitFee highest accepted fee for the trade | |
* @expiration when the order will expire if not filled | |
* @cancelId if the order is replacing an existing one | |
* @triggerPrice price the order if the order is a triggerable order | |
* @trailingPercent percent that the triggerPrice trails the index price of the market | |
* @param positionId associated with the order | |
*/ | |
placeOrder: async (market, side, type, timeInForce, postOnly, size, price, expiration, clientId = 1) => { | |
console.log('A dydx order was received:',market, side, type, timeInForce, postOnly, size, price, expiration) | |
if (!inited) await init() | |
try { | |
if (clientId === 1) { | |
const account = (await client1.private.getAccount(signer1.address)).account | |
const user = (await client1.private.getUser()).user | |
let req = { | |
market: market, | |
side: side.toUpperCase(), | |
type: type.toUpperCase(), | |
timeInForce: timeInForce, | |
postOnly: postOnly, | |
size: size, | |
price: price, | |
limitFee: user.takerFeeRate, | |
expiration: expiration | |
} | |
const order = await client1.private.createOrder(req, account.positionId) | |
return order | |
} else if (clientId === 2) { | |
const account = (await client2.private.getAccount(signer2.address)).account | |
const user = (await client2.private.getUser()).user | |
let req = { | |
market: market, | |
side: side.toUpperCase(), | |
type: type.toUpperCase(), | |
timeInForce: timeInForce, | |
postOnly: postOnly, | |
size: size, | |
price: price, | |
limitFee: user.takerFeeRate, | |
expiration: expiration | |
} | |
const order = await client2.private.createOrder(req, account.positionId) | |
return order | |
} | |
} catch (error) { | |
console.log(error) | |
console.log('An error occurred placing an order') | |
console.log(Object.keys(error)) | |
} | |
}, | |
cancelOrder: async (orderId, clientId = 1) => { | |
try { | |
if (!inited) await init() | |
if (clientId === 1) { | |
const result = await client1.private.cancelOrder(orderId) | |
return result.cancelOrder | |
} else if (clientId === 2) { | |
const result = await client2.private.cancelOrder(orderId) | |
return result.cancelOrder | |
} | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve apiKeys') | |
} | |
}, | |
cancelAllOrders: async (market, clientId = 1) => { | |
try { | |
if (!inited) await init() | |
if (clientId === 1) { | |
const result = await client1.private.cancelAllOrders(market) | |
return result | |
} else if (clientId === 2) { | |
const result = await client2.private.cancelAllOrders(market) | |
return result | |
} | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve apiKeys') | |
} | |
}, | |
getApikeys: async(clientId = 1) => { | |
try { | |
if (!inited) await init() | |
if (clientId === 1) { | |
const keys = await client1.private.getApiKeys() | |
return keys.apiKeys | |
} else if (clientId === 2) { | |
const keys = await client2.private.getApiKeys() | |
return keys.apiKeys | |
} | |
} catch (error) { | |
console.log(error) | |
console.log('Could not retrieve apiKeys') | |
} | |
} | |
} | |
// ; (async () => { | |
// await init() | |
// const orders = await module.exports.getActiveOrders('BTC-USD', 'BUY') | |
// console.log(orders) | |
// const fills = await module.exports.getFills('BTC-USD', iso8601(dateNowUTC()), 10) | |
// console.log(fills) | |
// for (let i = 0; i < fills.length; i++) { | |
// const order = await module.exports.getOrderById(fills[i].orderId) | |
// console.log(order) | |
// } | |
// const market = await module.exports.getMarket('BTC-USD') | |
// console.log(market) | |
// const days = 86400 * 1000 * 90 | |
// const past = iso8601(dateNowUTC() - days) | |
// const histo = await module.exports.getHistoricalPrices('BTC-USD', '1h', past, iso8601(dateNowUTC()), 10) | |
// console.log(histo) | |
// const funding = await module.exports.getPastFundingRates('BTC-USD', iso8601(dateNowUTC())) | |
// console.log(funding) | |
// const effectiveBeforeOrAt = iso8601(dateNowUTC()) | |
// const fundingPayments = await module.exports.getFundingPayments('BTC-USD', 10, effectiveBeforeOrAt) | |
// console.log(fundingPayments) | |
// const account = await module.exports.getAccount() | |
// console.log(account) | |
// const accounts = await module.exports.getAccounts() | |
// console.log(accounts) | |
// const positions = await module.exports.getPositions('BTC-USD', 'OPEN', 100, iso8601(dateNowUTC())) | |
// console.log(positions) | |
// const apiKeys = await module.exports.getApikeys() | |
// console.log(apiKeys) | |
/* | |
// create an order setup | |
const market = await module.exports.getMarket('BTC-USD') // last price of btc | |
const user = (await client1.private.getUser()).user // get fee for user | |
const account = (await client1.private.getAccount(signer1.address)).account // get positionId | |
const plus30m = iso8601(dateNowUTC() + 1800000) // expiration time | |
const response = await client1.private.getPositions({ | |
market: 'BTC-USD', | |
status: 'OPEN', | |
limit: 10, | |
createdBeforeOrAt: iso8601(dateNowUTC()), | |
}) | |
if (response.positions.length > 0) { | |
let p = response.positions[0] | |
console.log(p) | |
// lets close whatever is open at market: | |
let side | |
switch (p.side) { | |
case "SHORT": | |
side = "BUY" | |
break; | |
case "LONG": | |
side = "SELL" | |
break; | |
default: return; | |
} | |
const order = await module.exports.newOrder('BTC-USD', side, 'MARKET', 'FOK', false, String(Math.abs(p.size)), String(Math.floor(market.indexPrice)), user.takerFeeRate, plus30m, account.positionId) | |
console.log(order) | |
} | |
*/ | |
// cancel order setup | |
// const orders = await module.exports.getActiveOrders('BTC-USD', 'BUY') | |
// const result = await module.exports.cancelOrder(orders[0].id) | |
// console.log(result) | |
// const result = await module.exports.cancelAllOrders('ETH-USD') | |
// console.log(result) | |
// })() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
dateutils.js