Skip to content

Commit 7cc82e8

Browse files
committed
initial working with tardis orderbook data
1 parent d39662f commit 7cc82e8

File tree

5 files changed

+565
-24
lines changed

5 files changed

+565
-24
lines changed

index.ts

+73-19
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Setup provider (see anchor docs for more instructions on setting up a provider using your wallet)
2-
import * as anchor from "@project-serum/anchor";
3-
import * as zo from "@zero_one/client";
4-
import { Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js";
2+
import { default as zo } from "@zero_one/client";
3+
import { ConfirmOptions, Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js";
54
import { TpuClient } from "tpu-client";
65
import { config } from "dotenv";
7-
import { Program } from "@project-serum/anchor";
8-
import { FundingInfo, OrderType } from "@zero_one/client";
9-
6+
import { createProgram, createProvider, FundingInfo, IDL, OrderType, Zo } from "@zero_one/client";
7+
import { fork, ChildProcess } from 'child_process'
8+
import { Spreads, Spread } from "./tardis";
9+
import * as anchor from "@project-serum/anchor";
1010

1111
config({path: './.env.local'});
1212

@@ -29,12 +29,25 @@ export interface IWallet {
2929
publicKey: PublicKey;
3030
}
3131

32-
export declare class Wallet implements IWallet {
32+
class Wallet {
3333
readonly payer: Keypair;
34-
constructor(payer: Keypair);
35-
signTransaction(tx: Transaction): Promise<Transaction>;
36-
signAllTransactions(txs: Transaction[]): Promise<Transaction[]>;
37-
get publicKey(): PublicKey;
34+
35+
constructor(payer) {
36+
this.payer = payer;
37+
}
38+
async signTransaction(tx: Transaction) {
39+
tx.partialSign(this.payer);
40+
return tx;
41+
}
42+
async signAllTransactions(txs: Array<Transaction>) {
43+
return txs.map((t) => {
44+
t.partialSign(this.payer);
45+
return t;
46+
});
47+
}
48+
get publicKey() {
49+
return this.payer.publicKey;
50+
}
3851
}
3952

4053
// setup wallet
@@ -80,15 +93,17 @@ class MarketMaker {
8093
tpuClient: TpuClient
8194
provider: anchor.Provider
8295
idl: zo.Zo
83-
program: Program<zo.Zo>
96+
program: anchor.Program<zo.Zo>
8497
state: zo.State
8598
margin: zo.Margin
8699
running: boolean
100+
spreads: Spreads
87101
spread: number
88102
markets: Map<string, zo.ZoMarket>
89103
orderbooks: Map<string, Orderbook>
104+
tardis: ChildProcess
90105

91-
constructor(tpuClient: TpuClient, provider: anchor.Provider, idl: zo.Zo, program: Program<zo.Zo>, state: zo.State, margin: zo.Margin) {
106+
constructor(tpuClient: TpuClient, provider: anchor.Provider, idl: zo.Zo, program: anchor.Program<zo.Zo>, state: zo.State, margin: zo.Margin) {
92107
this.tpuClient = tpuClient;
93108
this.provider = provider;
94109
this.idl = idl;
@@ -100,16 +115,52 @@ class MarketMaker {
100115

101116
static async load() {
102117
const tpuClient = await TpuClient.load(new Connection(process.env.RPC_URL));
103-
const provider = new anchor.Provider( tpuClient.connection, botWallet, { commitment: 'processed' } );
104-
const idl = await anchor.Program.fetchIdl(new PublicKey(zo.ZERO_ONE_MAINNET_PROGRAM_ID), provider) as zo.Zo;
105-
const program = new anchor.Program(idl, zo.ZERO_ONE_MAINNET_PROGRAM_ID, provider) as Program<zo.Zo>;
106-
const state = await zo.State.load(program, zo.ZO_MAINNET_STATE_KEY) as zo.State;
107-
const margin = await zo.Margin.create(program, state) as zo.Margin;
118+
const provider = createProvider( tpuClient.connection, botWallet, { commitment: 'processed' } );
119+
const program = createProgram(provider, zo.Cluster.Mainnet);
120+
const state = await (zo.State).load(program, zo.ZO_MAINNET_STATE_KEY) as zo.State;
121+
const margin = await zo.Margin.load(program, state) as zo.Margin;
108122

109-
return new MarketMaker(tpuClient, provider, idl, program, state, margin);
123+
return new MarketMaker(tpuClient, provider, zo.IDL, program, state, margin);
110124
}
111125

112126

127+
public startTardis() {
128+
if(!this.tardis)
129+
this.tardis = fork('./tardis.ts', [], { stdio: ['pipe', 'pipe', 'pipe', 'ipc']})
130+
131+
if(this.tardis.stderr)
132+
this.tardis.stderr.on('data', (data : Buffer) => {
133+
console.log(data.toString());
134+
})
135+
136+
this.tardis.on('close', (code, sig) => {
137+
this.tardis.kill();
138+
delete this.tardis
139+
this.startTardis();
140+
})
141+
142+
if(this.tardis.stdout)
143+
this.tardis.stdout.on('data', (data: Buffer) => {
144+
console.log(data.toString());
145+
})
146+
147+
this.tardis.on('message', (data : string) => {
148+
let d = JSON.parse(data);
149+
switch(d.type) {
150+
case 'started':
151+
break;
152+
case 'data':
153+
break;
154+
case 'spreads':
155+
this.spreads = d.spreads as Spreads;
156+
console.log(this.spreads);
157+
break;
158+
case 'error':
159+
console.error(d.data);
160+
break;
161+
}
162+
})
163+
}
113164

114165
public stop() {
115166
this.running = false;
@@ -205,5 +256,8 @@ class MarketMaker {
205256

206257
}
207258

259+
MarketMaker.load().then(marketMaker => {
260+
marketMaker.startTardis();
261+
});
208262

209263

package.json

+13-3
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,25 @@
22
"name": "zo-mm",
33
"version": "1.0.0",
44
"description": "",
5-
"main": "index.js",
5+
"type": "module",
6+
"exports": [
7+
"./index.ts",
8+
"./tardis.ts"
9+
],
610
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
11+
"start": "node --loader ts-node/esm ./index.ts"
812
},
913
"author": "",
1014
"license": "ISC",
1115
"dependencies": {
16+
"@solana/web3.js": "^1.41.4",
1217
"@zero_one/client": "file:zo-client",
1318
"dotenv": "^16.0.0",
14-
"tpu-client": "^1.0.4"
19+
"tardis-dev": "^13.2.0",
20+
"tpu-client": "^1.0.4",
21+
"ts-node": "^10.7.0"
22+
},
23+
"devDependencies": {
24+
"typescript": "^4.6.4"
1525
}
1626
}

tardis.ts

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { streamNormalized, normalizeBookChanges, combine, compute, computeBookSnapshots, StreamNormalizedOptions, Exchange, BookPriceLevel, Optional } from 'tardis-dev'
2+
3+
4+
5+
const exchangesToStream = [
6+
{ exchange: 'bitmex', symbols: ['XBTUSD'] } as StreamNormalizedOptions<'bitmex'>,
7+
{ exchange: 'deribit' as Exchange, symbols: ['BTC-PERPETUAL'] } as StreamNormalizedOptions<'deribit'>,
8+
{ exchange: 'cryptofacilities' as Exchange, symbols: ['PI_XBTUSD'] } as StreamNormalizedOptions<'cryptofacilities'>,
9+
{ exchange: 'ftx' as Exchange, symbols: ['BTC-PERP']} as StreamNormalizedOptions<'ftx'>,
10+
{ exchange: 'binance-futures' as Exchange, symbols: ['btcusdt']} as StreamNormalizedOptions<'binance-futures'>
11+
]
12+
13+
const realTimeStreams = exchangesToStream.map((e) => {
14+
return streamNormalized(e, normalizeBookChanges)
15+
})
16+
17+
const messages = combine(...realTimeStreams)
18+
19+
const realTimeQuoteComputable = computeBookSnapshots({
20+
depth: 1,
21+
interval: 0,
22+
name: 'realtime_quote'
23+
})
24+
25+
const messagesWithQuotes = compute(messages, realTimeQuoteComputable)
26+
27+
const spreads = {} as Spreads
28+
29+
export interface Spreads {
30+
[key: string]: Spread
31+
}
32+
export interface Spread {
33+
spread: number,
34+
bestBid: Optional<BookPriceLevel>,
35+
bestAsk: Optional<BookPriceLevel>
36+
}
37+
38+
(async() => {
39+
// update spreads info real-time
40+
for await (const message of messagesWithQuotes) {
41+
if(!process.send) process.exit()
42+
if (message.type === 'book_snapshot') {
43+
spreads[message.exchange] = {
44+
spread: message.asks[0].price - message.bids[0].price,
45+
bestBid: message.bids[0],
46+
bestAsk: message.asks[0]
47+
} as Spread
48+
process.send(JSON.stringify({ type: 'spreads', spreads }));
49+
}
50+
}
51+
52+
})();

tsconfig.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"compilerOptions": {
3+
"module": "ES2020",
4+
"target": "es6",
5+
"esModuleInterop": true,
6+
"declaration": true,
7+
"outDir": "./lib",
8+
"moduleResolution": "node",
9+
"skipLibCheck": true,
10+
"allowJs": true,
11+
"allowSyntheticDefaultImports": true
12+
},
13+
"include": ["./"],
14+
"exclude": ["node_modules"]
15+
}

0 commit comments

Comments
 (0)