-
Notifications
You must be signed in to change notification settings - Fork 6
/
market-maker.js
155 lines (132 loc) · 5.29 KB
/
market-maker.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/env node
const chalk = require('chalk')
const ethers = require('ethers')
const _ = require('lodash')
const program = require('commander')
const BigNumber = require('bignumber.js')
const Saturn = require('@saturnnetwork/saturn.js').Saturn
const Strategy = require('@saturnnetwork/market-maker-strategy').MarketMaker
const version = require('./package.json').version
const saturnApi = 'https://ticker.saturn.network/api/v2'
const pipeline = async (funcs) => {
return await funcs.reduce((promise, func) => {
return promise.then(result => {
return func().then(Array.prototype.concat.bind(result))
})
}, Promise.resolve([]))
}
async function makeNewOrder(elem, saturn, botconfig) {
let executor = saturn[elem.blockchain.toLowerCase()]
let tx = await executor
.newOrder(botconfig.token, elem.order_type, elem.amount, elem.price)
await saturn.query.awaitOrderTx(tx, executor)
}
async function makeNewTrade(elem, saturn, botconfig) {
let executor = saturn[elem.blockchain.toLowerCase()]
let tx = await executor.newTrade(elem.amount, elem.order_tx)
await saturn.query.awaitTradeTx(tx, executor)
}
async function makeNewCancel(elem, saturn, botconfig) {
let executor = saturn[elem.blockchain.toLowerCase()]
let order = await saturn.query.getOrderByTx(elem.order_tx, elem.blockchain)
let tx = await executor.cancelOrder(order.order_id, order.contract)
await saturn.query.awaitTransaction(tx, executor, `Cancelling order ${elem.order_tx}`)
}
async function execute(actions, saturn, botconfig) {
let updates = _.map(actions, elem => {
if (elem.type === 'NewOrder') {
return async () => await makeNewOrder(elem, saturn, botconfig)
} else if (elem.type === 'Trade') {
return async () => await makeNewTrade(elem, saturn, botconfig)
} else if (elem.type === 'CancelOrder') {
return async () => await makeNewCancel(elem, saturn, botconfig)
} else {
console.log('Unknown event type')
return () => new Promise()
}
})
await pipeline(updates).catch(console.error.bind(console))
}
function makeBotConfig(botconfig) {
let rpcurl = botconfig.provider || rpcNode(botconfig.blockchain)
let chainId = getChainId(botconfig.blockchain)
let provider = new ethers.providers.JsonRpcProvider(rpcurl, { chainId: chainId, name: botconfig.blockchain })
let saturn = new Saturn(saturnApi)
botconfig.provider = provider
botconfig.saturn = saturn
botconfig.fundMinimum = new BigNumber(botconfig.fundMinimum)
botconfig.tokenLimit = new BigNumber(botconfig.tokenLimit)
botconfig.spread = new BigNumber(botconfig.spread)
botconfig.dustCutoff = new BigNumber(botconfig.dustCutoff)
botconfig.bandSize = new BigNumber(botconfig.bandSize)
return botconfig
}
function getChainId(chain) {
if (chain === 'ETC') { return 61 }
if (chain === 'ETH') { return 1 }
console.log('Unknown chainId for chain', chain)
process.exit(1)
}
function rpcNode(chain) {
if (chain === 'ETC') { return 'https://www.ethercluster.com/etc' }
if (chain === 'ETH') { return 'https://mainnet.infura.io/mew' }
console.log('Unknown chainId for chain', chain)
process.exit(1)
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function makeSaturnClient(blockchain, program, wallet) {
let rpcnode = rpcNode(blockchain)
let chainId = getChainId(blockchain)
let provider = new ethers.providers.JsonRpcProvider(rpcnode, { chainId: chainId, name: blockchain })
let saturn
if (blockchain === 'ETC') {
saturn = new Saturn(saturnApi, { etc: wallet.connect(provider) })
} else {
saturn = new Saturn(saturnApi, { eth: wallet.connect(provider) })
}
return saturn
}
program
.version(version, '-v, --version')
.description('Market making bot for Saturn Network')
.option('-p, --pkey [pkey]', 'Private key of the wallet to use for trading')
.option('-m, --mnemonic [mnemonic]', 'Mnemonic (i.e. from Saturn Wallet) of the wallet to use for trading')
.option('-i, --walletid [walletid]', 'If using a mnemonic, choose which wallet to use. Default is Account 2 of Saturn Wallet / MetaMask.', 2)
.option('-j, --json [json]', 'Trading bot config file')
.option('-d, --delay [delay]', 'Polling delay in seconds', 60)
.parse(process.argv)
if (!program.mnemonic && !program.pkey) {
console.error('At least one of [pkey], [mnemonic] must be supplied')
process.exit(1)
}
if (program.mnemonic && program.pkey) {
console.error('Only one of [pkey], [mnemonic] must be supplied')
process.exit(1)
}
let wallet
if (program.mnemonic) {
let walletid = parseInt(program.walletid) - 1
wallet = ethers.Wallet.fromMnemonic(program.mnemonic, `m/44'/60'/0'/0/${walletid}`)
} else {
wallet = new ethers.Wallet(program.pkey)
}
if (!program.json) {
console.error('Must specify bot config .json file location')
process.exit(1)
}
let botconfig = makeBotConfig(require(program.json))
console.log(chalk.green(`Loading market-maker bot v${version} ...`))
let strategy = new Strategy(botconfig, wallet.address)
let saturn = makeSaturnClient(botconfig.blockchain, program, wallet)
let trade = async function() {
try {
actions = await strategy.getActions()
if (actions.length) { await execute(actions, saturn, botconfig) }
} catch(e) {
console.error(e)
}
setTimeout(trade, parseInt(program.delay) * 1000)
};
(async () => await trade())()