@flexemarkets/fm-sdk 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/stomp.js ADDED
@@ -0,0 +1,275 @@
1
+ /**
2
+ * WebSocket STOMP event listener for Flexemarkets.
3
+ *
4
+ * Implements STOMP 1.2 framing over WebSocket, matching the Python
5
+ * EventListener / Java StompListener behaviour.
6
+ */
7
+ import WebSocket from "ws";
8
+ const HEARTBEAT_MS = 30_000;
9
+ const NULL = "\x00";
10
+ export function encodeFrame(frame) {
11
+ const lines = [frame.command];
12
+ for (const [k, v] of Object.entries(frame.headers)) {
13
+ lines.push(`${k}:${v}`);
14
+ }
15
+ lines.push("");
16
+ lines.push(frame.body);
17
+ return lines.join("\n") + NULL;
18
+ }
19
+ export function decodeFrame(raw) {
20
+ // Strip trailing NUL and whitespace
21
+ raw = raw.replace(/\x00+$/, "");
22
+ // Split command + headers from body at the first blank line
23
+ const headerEnd = raw.indexOf("\n\n");
24
+ let headerSection;
25
+ let body;
26
+ if (headerEnd < 0) {
27
+ headerSection = raw;
28
+ body = "";
29
+ }
30
+ else {
31
+ headerSection = raw.substring(0, headerEnd);
32
+ body = raw.substring(headerEnd + 2);
33
+ }
34
+ const lines = headerSection.split("\n");
35
+ const command = lines[0] ?? "";
36
+ const headers = {};
37
+ for (const line of lines.slice(1)) {
38
+ const idx = line.indexOf(":");
39
+ if (idx >= 0) {
40
+ headers[line.substring(0, idx)] = line.substring(idx + 1);
41
+ }
42
+ }
43
+ return { command, headers, body };
44
+ }
45
+ // ---------------------------------------------------------------------------
46
+ // Event parsing — mirrors Python _parse_event / Java EventParser
47
+ // ---------------------------------------------------------------------------
48
+ const MESSAGE_TYPE = "message-type";
49
+ function parseEvent(frame, parseHolding, parseOrder) {
50
+ const msgType = frame.headers[MESSAGE_TYPE];
51
+ if (msgType === undefined)
52
+ return null;
53
+ let data;
54
+ try {
55
+ data = frame.body ? JSON.parse(frame.body) : null;
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ switch (msgType) {
61
+ case "VERSION":
62
+ return parseVersion(data);
63
+ case "SESSION-LIST":
64
+ return parseSessionList(data);
65
+ case "SESSION-UPDATE":
66
+ return parseSession(data);
67
+ case "HOLDING-UPDATE":
68
+ return parseHolding(data);
69
+ case "ORDERS-UPDATE":
70
+ return parseOrders(data, parseOrder);
71
+ default:
72
+ return null;
73
+ }
74
+ }
75
+ function parseVersion(data) {
76
+ if (typeof data === "object" && data !== null && "version" in data) {
77
+ return { version: data.version ?? 0 };
78
+ }
79
+ return { version: typeof data === "number" ? data : 0 };
80
+ }
81
+ function parseSession(data) {
82
+ return {
83
+ marketplaceId: data.marketplaceId ?? 0,
84
+ allocationId: data.allocationId ?? 0,
85
+ id: data.id ?? 0,
86
+ original: data.original ?? 0,
87
+ state: data.state ?? null,
88
+ name: data.name ?? null,
89
+ description: data.description ?? null,
90
+ openDate: data.openDate ?? null,
91
+ closeDate: data.closeDate ?? null,
92
+ };
93
+ }
94
+ function parseSessionList(data) {
95
+ if (Array.isArray(data)) {
96
+ return data.map((s) => parseSession(s));
97
+ }
98
+ return [];
99
+ }
100
+ function parseOrders(data, parseOrder) {
101
+ if (Array.isArray(data)) {
102
+ return data.map((o) => parseOrder(o));
103
+ }
104
+ return [];
105
+ }
106
+ // ---------------------------------------------------------------------------
107
+ // EventListener — manages WS + STOMP connection
108
+ // ---------------------------------------------------------------------------
109
+ export class EventListener {
110
+ _wsUrl;
111
+ _bearerToken;
112
+ _marketplaceId;
113
+ _callback;
114
+ _clientDescription;
115
+ _parseHolding;
116
+ _parseOrder;
117
+ _ws = null;
118
+ _closed = false;
119
+ _subscriptionCounter = 0;
120
+ constructor(wsUrl, bearerToken, marketplaceId, callback, clientDescription, parseHolding, parseOrder) {
121
+ this._wsUrl = wsUrl;
122
+ this._bearerToken = bearerToken;
123
+ this._marketplaceId = marketplaceId;
124
+ this._callback = callback;
125
+ this._clientDescription = clientDescription;
126
+ this._parseHolding = parseHolding;
127
+ this._parseOrder = parseOrder;
128
+ }
129
+ // -- public API ------------------------------------------------------------
130
+ start() {
131
+ return new Promise((resolve, reject) => {
132
+ this._ws = this._connect();
133
+ this._ws.on("open", () => {
134
+ try {
135
+ this._stompConnect();
136
+ }
137
+ catch (err) {
138
+ reject(err);
139
+ return;
140
+ }
141
+ // Wait for CONNECTED frame then subscribe
142
+ this._ws.once("message", (raw) => {
143
+ const reply = decodeFrame(raw.toString());
144
+ if (reply.command !== "CONNECTED" && reply.command !== "") {
145
+ // unexpected but continue
146
+ }
147
+ this._subscribe();
148
+ this._receiveLoop();
149
+ resolve();
150
+ });
151
+ });
152
+ this._ws.on("error", (err) => {
153
+ if (!this._closed) {
154
+ reject(err);
155
+ }
156
+ });
157
+ });
158
+ }
159
+ async reconnect() {
160
+ while (!this._closed) {
161
+ try {
162
+ this._disconnect();
163
+ await this.start();
164
+ return;
165
+ }
166
+ catch {
167
+ await new Promise((r) => setTimeout(r, 2000));
168
+ }
169
+ }
170
+ }
171
+ close() {
172
+ if (this._closed)
173
+ return;
174
+ this._closed = true;
175
+ this._disconnect();
176
+ }
177
+ // -- WebSocket connection --------------------------------------------------
178
+ _connect() {
179
+ return new WebSocket(this._wsUrl, ["v12.stomp", "v11.stomp", "v10.stomp"], {
180
+ headers: {
181
+ Authorization: this._bearerToken,
182
+ },
183
+ maxPayload: 128 * 1024 * 1024,
184
+ });
185
+ }
186
+ _disconnect() {
187
+ if (this._ws !== null) {
188
+ try {
189
+ this._ws.removeAllListeners();
190
+ this._ws.close();
191
+ }
192
+ catch {
193
+ // ignore
194
+ }
195
+ this._ws = null;
196
+ }
197
+ }
198
+ // -- STOMP framing ---------------------------------------------------------
199
+ _nextId() {
200
+ this._subscriptionCounter += 1;
201
+ return `sub-${this._subscriptionCounter}`;
202
+ }
203
+ _stompConnect() {
204
+ const frame = {
205
+ command: "CONNECT",
206
+ headers: {
207
+ "accept-version": "1.2,1.1,1.0",
208
+ "heart-beat": `${HEARTBEAT_MS},${HEARTBEAT_MS}`,
209
+ "agent-description": this._clientDescription,
210
+ "marketplace-id": String(this._marketplaceId),
211
+ },
212
+ body: "",
213
+ };
214
+ this._ws.send(encodeFrame(frame));
215
+ }
216
+ _subscribe() {
217
+ const resource = `/marketplaces/${this._marketplaceId}`;
218
+ for (const dest of [
219
+ `/user/queue${resource}`,
220
+ `/topic${resource}`,
221
+ `/app${resource}`,
222
+ ]) {
223
+ const frame = {
224
+ command: "SUBSCRIBE",
225
+ headers: {
226
+ id: this._nextId(),
227
+ destination: dest,
228
+ },
229
+ body: "",
230
+ };
231
+ this._ws.send(encodeFrame(frame));
232
+ }
233
+ }
234
+ // -- receive loop ----------------------------------------------------------
235
+ _receiveLoop() {
236
+ this._ws.on("message", (raw) => {
237
+ const data = raw.toString();
238
+ if (!data || data === "\n")
239
+ return; // STOMP heartbeat
240
+ const frame = decodeFrame(data);
241
+ if (frame.command === "MESSAGE") {
242
+ const event = parseEvent(frame, this._parseHolding, this._parseOrder);
243
+ if (event !== null) {
244
+ this._callback(event);
245
+ }
246
+ }
247
+ else if (frame.command === "ERROR") {
248
+ this._callback({
249
+ kind: "ws-exception",
250
+ command: frame.command,
251
+ headers: frame.headers,
252
+ body: frame.body,
253
+ exception: new Error(frame.headers.message ?? "STOMP ERROR"),
254
+ });
255
+ }
256
+ });
257
+ this._ws.on("close", () => {
258
+ if (!this._closed) {
259
+ this._callback({
260
+ kind: "transport-error",
261
+ exception: new Error("WebSocket connection closed"),
262
+ });
263
+ }
264
+ });
265
+ this._ws.on("error", (err) => {
266
+ if (!this._closed) {
267
+ this._callback({
268
+ kind: "transport-error",
269
+ exception: err,
270
+ });
271
+ }
272
+ });
273
+ }
274
+ }
275
+ //# sourceMappingURL=stomp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stomp.js","sourceRoot":"","sources":["../src/stomp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * fm-ticker — live order book and trade history display.
4
+ *
5
+ * Port of python/ticker.py.
6
+ */
7
+ export {};
package/dist/ticker.js ADDED
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * fm-ticker — live order book and trade history display.
4
+ *
5
+ * Port of python/ticker.py.
6
+ */
7
+ import { Flexemarkets } from "./client.js";
8
+ import { OrderBooks } from "./orderbook.js";
9
+ import { MarketplaceTrades } from "./trades.js";
10
+ import { SESSION_STATE_CLOSED } from "./types.js";
11
+ const TRADE_DISPLAY_COUNT = 5;
12
+ function price(value) {
13
+ if (value < 0)
14
+ return " -";
15
+ return `$${(value / 100).toFixed(2).padStart(5)}`;
16
+ }
17
+ function spread(bid, ask) {
18
+ if (bid < 0 || ask < 0)
19
+ return " -";
20
+ return `$${((ask - bid) / 100).toFixed(2).padStart(5)}`;
21
+ }
22
+ function tradePrices(prices, count) {
23
+ const recent = prices.length > count ? prices.slice(-count) : prices;
24
+ return [...recent]
25
+ .reverse()
26
+ .map((p) => `$${(p / 100).toFixed(2)}`)
27
+ .join(" ");
28
+ }
29
+ function display(books, trades, session, endpointUrl = "") {
30
+ const state = session?.state ?? "---";
31
+ const lines = [];
32
+ lines.push("\x1b[2J\x1b[H"); // clear screen, cursor home
33
+ lines.push(`fm-ticker ${endpointUrl}`);
34
+ lines.push(state.padStart(59));
35
+ lines.push("");
36
+ lines.push(` ${"Symbol".padStart(6)} ${"Bid".padStart(6)} ${"Ask".padStart(6)} ${"Spread".padStart(6)} Last trades`);
37
+ lines.push(` ${"------".padStart(6)} ${"------".padStart(6)} ${"------".padStart(6)} ${"------".padStart(6)} -----------`);
38
+ const sorted = [...books.collection()].sort((a, b) => a.marketId - b.marketId);
39
+ for (const book of sorted) {
40
+ const bid = book.bestBuyPrice();
41
+ const ask = book.bestSellPrice();
42
+ const symbol = book.symbol ?? "?";
43
+ const recent = trades.get(book.marketId).mostRecentPrices();
44
+ lines.push(` ${symbol.padStart(6)} ${price(bid)} ${price(ask)} ${spread(bid, ask)} ${tradePrices(recent, TRADE_DISPLAY_COUNT)}`);
45
+ }
46
+ lines.push("");
47
+ process.stdout.write(lines.join("\n"));
48
+ }
49
+ function isOrderArray(event) {
50
+ return Array.isArray(event) && (event.length === 0 || "supplier" in event[0]);
51
+ }
52
+ function isSession(event) {
53
+ return (typeof event === "object" &&
54
+ !Array.isArray(event) &&
55
+ "state" in event &&
56
+ "marketplaceId" in event &&
57
+ "allocationId" in event);
58
+ }
59
+ function isTransportError(event) {
60
+ return typeof event === "object" && "kind" in event && event.kind === "transport-error";
61
+ }
62
+ async function main() {
63
+ // Parse CLI args
64
+ const args = process.argv.slice(2);
65
+ let credential = null;
66
+ let endpoint = null;
67
+ for (let i = 0; i < args.length; i++) {
68
+ if ((args[i] === "-C" || args[i] === "--credential") && i + 1 < args.length) {
69
+ credential = args[++i];
70
+ }
71
+ else if ((args[i] === "-E" || args[i] === "--endpoint") && i + 1 < args.length) {
72
+ endpoint = args[++i];
73
+ }
74
+ }
75
+ const fm = await Flexemarkets.connect(credential, endpoint, "fm-ticker");
76
+ try {
77
+ const marketplaceId = fm.endpointMarketplaceId;
78
+ const markets = await fm.markets(marketplaceId);
79
+ markets.sort((a, b) => a.id - b.id);
80
+ const books = new OrderBooks(markets);
81
+ const marketTrades = new MarketplaceTrades(markets);
82
+ const endpointUrl = fm.endpointUrl;
83
+ let session = null;
84
+ display(books, marketTrades, session, endpointUrl);
85
+ await fm.listen(marketplaceId, (event) => {
86
+ let redraw = false;
87
+ if (isOrderArray(event)) {
88
+ books.update(event);
89
+ marketTrades.update(event);
90
+ redraw = true;
91
+ }
92
+ else if (isSession(event)) {
93
+ session = event;
94
+ redraw = true;
95
+ if (event.state === SESSION_STATE_CLOSED) {
96
+ display(books, marketTrades, session, endpointUrl);
97
+ console.log("Session closed.");
98
+ fm.close();
99
+ process.exit(0);
100
+ }
101
+ }
102
+ else if (isTransportError(event)) {
103
+ process.stderr.write(`\nConnection lost: ${event.exception.message}\n`);
104
+ fm.reconnect();
105
+ }
106
+ if (redraw) {
107
+ display(books, marketTrades, session, endpointUrl);
108
+ }
109
+ });
110
+ // Keep alive — listen for Ctrl+C
111
+ process.on("SIGINT", () => {
112
+ console.log("\nStopped.");
113
+ fm.close();
114
+ process.exit(0);
115
+ });
116
+ // Keep the process alive
117
+ await new Promise(() => { });
118
+ }
119
+ catch (err) {
120
+ fm.close();
121
+ throw err;
122
+ }
123
+ }
124
+ main().catch((err) => {
125
+ console.error(err);
126
+ process.exit(1);
127
+ });
128
+ //# sourceMappingURL=ticker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticker.js","sourceRoot":"","sources":["../src/ticker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Trade history maintained from WebSocket order events.
3
+ *
4
+ * Port of fm.trades (Python) / fm.Trades (Java).
5
+ */
6
+ import type { Market, Order } from "./types.js";
7
+ /**
8
+ * Bounded FIFO queue of executed trades for a single market.
9
+ *
10
+ * Updated incrementally from WebSocket ORDERS-UPDATE events.
11
+ * Keeps the most recent `capacity` trades.
12
+ */
13
+ export declare class Trades {
14
+ readonly market: Market;
15
+ readonly capacity: number;
16
+ private readonly _container;
17
+ constructor(market: Market, capacity?: number);
18
+ get marketId(): number;
19
+ size(): number;
20
+ update(orders: Order[]): void;
21
+ private _append;
22
+ mostRecentTrades(): Order[];
23
+ mostRecentPrices(): number[];
24
+ drain(): Order[];
25
+ }
26
+ /**
27
+ * Container of Trades instances, one per market.
28
+ */
29
+ export declare class MarketplaceTrades {
30
+ private readonly _trades;
31
+ constructor(markets: Market[], capacity?: number);
32
+ update(orders: Order[]): void;
33
+ mostRecentPrices(): number[][];
34
+ collection(): Trades[];
35
+ get(marketId: number): Trades;
36
+ }
package/dist/trades.js ADDED
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Trade history maintained from WebSocket order events.
3
+ *
4
+ * Port of fm.trades (Python) / fm.Trades (Java).
5
+ */
6
+ import { isCancel, isConsumed, isSplit, isSymbol } from "./order-utils.js";
7
+ /**
8
+ * Bounded FIFO queue of executed trades for a single market.
9
+ *
10
+ * Updated incrementally from WebSocket ORDERS-UPDATE events.
11
+ * Keeps the most recent `capacity` trades.
12
+ */
13
+ export class Trades {
14
+ market;
15
+ capacity;
16
+ _container = [];
17
+ constructor(market, capacity = 100) {
18
+ if (capacity < 1)
19
+ throw new Error("Capacity must be greater than zero.");
20
+ this.market = market;
21
+ this.capacity = capacity;
22
+ }
23
+ get marketId() {
24
+ return this.market.id;
25
+ }
26
+ size() {
27
+ return this._container.length;
28
+ }
29
+ // -- update from WebSocket events ------------------------------------------
30
+ update(orders) {
31
+ const consumers = new Map();
32
+ for (const order of orders) {
33
+ if (!isSymbol(this.market.symbol, order))
34
+ continue;
35
+ if (isCancel(order))
36
+ continue;
37
+ if (isSplit(order))
38
+ continue;
39
+ if (isConsumed(order)) {
40
+ consumers.set(order.id, order);
41
+ const consumer = consumers.get(order.consumer);
42
+ if (consumer !== undefined) {
43
+ // The resting order is the one with the older original ID
44
+ if (order.original < consumer.original) {
45
+ this._append(order);
46
+ }
47
+ else {
48
+ this._append(consumer);
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ _append(order) {
55
+ this._container.push(order);
56
+ while (this._container.length > this.capacity) {
57
+ this._container.shift();
58
+ }
59
+ }
60
+ // -- query -----------------------------------------------------------------
61
+ mostRecentTrades() {
62
+ return [...this._container];
63
+ }
64
+ mostRecentPrices() {
65
+ return this._container.map((o) => o.price);
66
+ }
67
+ drain() {
68
+ const trades = [...this._container];
69
+ this._container.length = 0;
70
+ return trades;
71
+ }
72
+ }
73
+ /**
74
+ * Container of Trades instances, one per market.
75
+ */
76
+ export class MarketplaceTrades {
77
+ _trades = new Map();
78
+ constructor(markets, capacity = 100) {
79
+ for (const m of markets) {
80
+ this._trades.set(m.id, new Trades(m, capacity));
81
+ }
82
+ }
83
+ update(orders) {
84
+ for (const t of this._trades.values()) {
85
+ t.update(orders);
86
+ }
87
+ }
88
+ mostRecentPrices() {
89
+ return [...this._trades.values()]
90
+ .sort((a, b) => a.marketId - b.marketId)
91
+ .map((t) => t.mostRecentPrices());
92
+ }
93
+ collection() {
94
+ return [...this._trades.values()];
95
+ }
96
+ get(marketId) {
97
+ return this._trades.get(marketId);
98
+ }
99
+ }
100
+ //# sourceMappingURL=trades.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trades.js","sourceRoot":"","sources":["../src/trades.ts"],"names":[],"mappings":"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"}