@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.
@@ -0,0 +1,10 @@
1
+ /** Flexemarkets TypeScript SDK. */
2
+ export type { Person, Account, Token, Security, Holding, Market, Marketplace, Session, Order, ClientConnection, Version, ApiRoot, ConflictFailure, } from "./types.js";
3
+ export { SESSION_STATE_INIT, SESSION_STATE_OPEN, SESSION_STATE_PAUSED, SESSION_STATE_CLOSED, ORDER_TYPE_LIMIT, ORDER_TYPE_CANCEL, ORDER_SIDE_BUY, ORDER_SIDE_SELL, getSecurity, holdingUnits, priceRound, getLink, } from "./types.js";
4
+ export { Flexemarkets, FlexemarketsError, AuthenticationError, AuthorizationError, InvalidArgumentError, ConnectionFailedError, ConfigurationError, } from "./client.js";
5
+ export type { FlexemarketsOptions } from "./client.js";
6
+ export { isCancel, isLimit, isBuy, isSell, contra, isAvailable, isConsumed, isSplit, isSymbol, isSubmit, isResting, findOrder, } from "./order-utils.js";
7
+ export { OrderBook, OrderBooks } from "./orderbook.js";
8
+ export { Trades, MarketplaceTrades } from "./trades.js";
9
+ export { EventListener } from "./stomp.js";
10
+ export type { StompFrame, WsTransportError, WsException, FmEvent, EventCallback, } from "./stomp.js";
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ /** Flexemarkets TypeScript SDK. */
2
+ export { SESSION_STATE_INIT, SESSION_STATE_OPEN, SESSION_STATE_PAUSED, SESSION_STATE_CLOSED, ORDER_TYPE_LIMIT, ORDER_TYPE_CANCEL, ORDER_SIDE_BUY, ORDER_SIDE_SELL, getSecurity, holdingUnits, priceRound, getLink, } from "./types.js";
3
+ // Client
4
+ export { Flexemarkets, FlexemarketsError, AuthenticationError, AuthorizationError, InvalidArgumentError, ConnectionFailedError, ConfigurationError, } from "./client.js";
5
+ // Order utils
6
+ export { isCancel, isLimit, isBuy, isSell, contra, isAvailable, isConsumed, isSplit, isSymbol, isSubmit, isResting, findOrder, } from "./order-utils.js";
7
+ // Order book
8
+ export { OrderBook, OrderBooks } from "./orderbook.js";
9
+ // Trades
10
+ export { Trades, MarketplaceTrades } from "./trades.js";
11
+ // Events
12
+ export { EventListener } from "./stomp.js";
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAmBnC,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,WAAW,EACX,YAAY,EACZ,UAAU,EACV,OAAO,GACR,MAAM,YAAY,CAAC;AAEpB,SAAS;AACT,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAGrB,cAAc;AACd,OAAO,EACL,QAAQ,EACR,OAAO,EACP,KAAK,EACL,MAAM,EACN,MAAM,EACN,WAAW,EACX,UAAU,EACV,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,SAAS,GACV,MAAM,kBAAkB,CAAC;AAE1B,aAAa;AACb,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEvD,SAAS;AACT,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAExD,SAAS;AACT,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Order status utilities.
3
+ *
4
+ * Port of fm.order_utils (Python) / fm.OrderUtils (Java).
5
+ */
6
+ import { Order } from "./types.js";
7
+ export declare function isCancel(order: Order): boolean;
8
+ export declare function isLimit(order: Order): boolean;
9
+ export declare function isBuy(side: string): boolean;
10
+ export declare function isSell(side: string): boolean;
11
+ export declare function contra(side: string): string;
12
+ /** Order is resting on the book (consumer is null). */
13
+ export declare function isAvailable(order: Order): boolean;
14
+ /** Order has been matched with another order. */
15
+ export declare function isConsumed(order: Order): boolean;
16
+ /** Order has been split into multiple fills. */
17
+ export declare function isSplit(order: Order): boolean;
18
+ export declare function isSymbol(symbol: string | null, order: Order): boolean;
19
+ export declare function isSubmit(order: Order): boolean;
20
+ export declare function findOrder(orders: Order[], orderId: number | null | undefined): Order | null;
21
+ /** Determine if an order is currently resting on the book. */
22
+ export declare function isResting(orders: Order[], order: Order): boolean;
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Order status utilities.
3
+ *
4
+ * Port of fm.order_utils (Python) / fm.OrderUtils (Java).
5
+ */
6
+ import { ORDER_TYPE_CANCEL, ORDER_TYPE_LIMIT, ORDER_SIDE_BUY, ORDER_SIDE_SELL, } from "./types.js";
7
+ export function isCancel(order) {
8
+ return order.type?.toUpperCase() === ORDER_TYPE_CANCEL;
9
+ }
10
+ export function isLimit(order) {
11
+ return order.type?.toUpperCase() === ORDER_TYPE_LIMIT;
12
+ }
13
+ export function isBuy(side) {
14
+ return side.toUpperCase() === ORDER_SIDE_BUY;
15
+ }
16
+ export function isSell(side) {
17
+ return side.toUpperCase() === ORDER_SIDE_SELL;
18
+ }
19
+ export function contra(side) {
20
+ return isBuy(side) ? ORDER_SIDE_SELL : ORDER_SIDE_BUY;
21
+ }
22
+ /** Order is resting on the book (consumer is null). */
23
+ export function isAvailable(order) {
24
+ return order.consumer === null || order.consumer === undefined;
25
+ }
26
+ /** Order has been matched with another order. */
27
+ export function isConsumed(order) {
28
+ return order.consumer !== null && order.consumer !== undefined && order.consumer !== 0;
29
+ }
30
+ /** Order has been split into multiple fills. */
31
+ export function isSplit(order) {
32
+ return order.consumer !== null && order.consumer !== undefined && order.consumer === 0;
33
+ }
34
+ export function isSymbol(symbol, order) {
35
+ if (symbol === null || symbol === undefined)
36
+ return true;
37
+ return order.symbol?.toUpperCase() === symbol.toUpperCase();
38
+ }
39
+ export function isSubmit(order) {
40
+ return isCancel(order) || (order.id === order.original && order.id === order.supplier);
41
+ }
42
+ export function findOrder(orders, orderId) {
43
+ if (orderId === null || orderId === undefined)
44
+ return null;
45
+ for (const o of orders) {
46
+ if (o.id === orderId)
47
+ return o;
48
+ }
49
+ return null;
50
+ }
51
+ function isCancelled(orders, order) {
52
+ const consumer = findOrder(orders, order.consumer);
53
+ if (consumer !== null) {
54
+ if (order.type !== consumer.type)
55
+ return true;
56
+ }
57
+ return false;
58
+ }
59
+ function inTradeSet(orders, orderId) {
60
+ for (const o of orders) {
61
+ if (o.id === orderId)
62
+ return true;
63
+ }
64
+ return false;
65
+ }
66
+ function isTraded(orders, order) {
67
+ if (isLimit(order) && isConsumed(order)) {
68
+ const consumer = findOrder(orders, order.consumer);
69
+ if (consumer !== null && isLimit(consumer))
70
+ return true;
71
+ }
72
+ return false;
73
+ }
74
+ function firstChild(orders, order) {
75
+ for (const o of orders) {
76
+ if (order.id === o.original && !isSplit(o))
77
+ return o;
78
+ }
79
+ return null;
80
+ }
81
+ function isCreatedEarlier(order, consumer) {
82
+ return order.id < consumer.id;
83
+ }
84
+ function isOlder(orders, o1, o2) {
85
+ if (o1 === null)
86
+ return true;
87
+ if (o2 === null)
88
+ return false;
89
+ const o1In = inTradeSet(orders, o1.original);
90
+ const o2In = inTradeSet(orders, o2.original);
91
+ if (!o1In && o2In)
92
+ return true;
93
+ if (o1In && !o2In)
94
+ return false;
95
+ const o1Original = o1.id === o1.original ? o1 : findOrder(orders, o1.original);
96
+ const o2Original = o2.id === o2.original ? o2 : findOrder(orders, o2.original);
97
+ if (o1Original === null || o2Original === null) {
98
+ return o1Original === null;
99
+ }
100
+ return isCreatedEarlier(o1Original, o2Original);
101
+ }
102
+ function isSupplierOlder(orders, order) {
103
+ if (order === null)
104
+ return false;
105
+ const orderSupplier = findOrder(orders, order.supplier);
106
+ const consumer = findOrder(orders, order.consumer);
107
+ const consumerSupplierId = consumer !== null ? consumer.supplier : null;
108
+ const consumerSupplier = findOrder(orders, consumerSupplierId);
109
+ return isOlder(orders, orderSupplier, consumerSupplier);
110
+ }
111
+ /** Determine if an order is currently resting on the book. */
112
+ export function isResting(orders, order) {
113
+ // available order is resting
114
+ if (isAvailable(order))
115
+ return true;
116
+ // CANCEL order is not resting
117
+ if (isCancel(order))
118
+ return false;
119
+ // Cancelled LIMIT order is resting
120
+ if (isCancelled(orders, order))
121
+ return true;
122
+ // order with supplier not in trade-set is resting
123
+ if (!inTradeSet(orders, order.supplier))
124
+ return true;
125
+ // order supplier older than consumer supplier
126
+ if (isTraded(orders, order))
127
+ return isSupplierOlder(orders, order);
128
+ // split order with child younger than its consumer is resting
129
+ return isSupplierOlder(orders, firstChild(orders, order));
130
+ }
131
+ //# sourceMappingURL=order-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order-utils.js","sourceRoot":"","sources":["../src/order-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAEL,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,MAAM,UAAU,QAAQ,CAAC,KAAY;IACnC,OAAO,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,iBAAiB,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAY;IAClC,OAAO,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,gBAAgB,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,IAAY;IAChC,OAAO,IAAI,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,WAAW,EAAE,KAAK,eAAe,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,cAAc,CAAC;AACxD,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,WAAW,CAAC,KAAY;IACtC,OAAO,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC;AACjE,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,UAAU,CAAC,KAAY;IACrC,OAAO,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ,KAAK,CAAC,CAAC;AACzF,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,OAAO,CAAC,KAAY;IAClC,OAAO,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ,KAAK,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAqB,EAAE,KAAY;IAC1D,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACzD,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,MAAM,CAAC,WAAW,EAAE,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAY;IACnC,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,QAAQ,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAe,EAAE,OAAkC;IAC3E,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC3D,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC,EAAE,KAAK,OAAO;YAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,MAAe,EAAE,KAAY;IAChD,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACnD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;IAChD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CAAC,MAAe,EAAE,OAAe;IAClD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC,EAAE,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC;IACpC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,MAAe,EAAE,KAAY;IAC7C,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,QAAQ,KAAK,IAAI,IAAI,OAAO,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;IAC1D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CAAC,MAAe,EAAE,KAAY;IAC/C,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAY,EAAE,QAAe;IACrD,OAAO,KAAK,CAAC,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,OAAO,CAAC,MAAe,EAAE,EAAgB,EAAE,EAAgB;IAClE,IAAI,EAAE,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7B,IAAI,EAAE,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAE9B,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;IAE7C,IAAI,CAAC,IAAI,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,IAAI,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IAEhC,MAAM,UAAU,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;IAC/E,MAAM,UAAU,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;IAE/E,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QAC/C,OAAO,UAAU,KAAK,IAAI,CAAC;IAC7B,CAAC;IACD,OAAO,gBAAgB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,eAAe,CAAC,MAAe,EAAE,KAAmB;IAC3D,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAEjC,MAAM,aAAa,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAEnD,MAAM,kBAAkB,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IACxE,MAAM,gBAAgB,GAAG,SAAS,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAE/D,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;AAC1D,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,SAAS,CAAC,MAAe,EAAE,KAAY;IACrD,6BAA6B;IAC7B,IAAI,WAAW,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,8BAA8B;IAC9B,IAAI,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAElC,mCAAmC;IACnC,IAAI,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE5C,kDAAkD;IAClD,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAErD,8CAA8C;IAC9C,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAEnE,8DAA8D;IAC9D,OAAO,eAAe,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Order book maintained from WebSocket order events.
3
+ *
4
+ * Port of fm.orderbook (Python) / fm.OrderBook (Java).
5
+ */
6
+ import type { Market, Order } from "./types.js";
7
+ /**
8
+ * Aggregated price-level order book for a single market.
9
+ *
10
+ * Updated incrementally from WebSocket ORDERS-UPDATE events.
11
+ * Buys are sorted highest-first (best bid), sells lowest-first (best ask).
12
+ */
13
+ export declare class OrderBook {
14
+ readonly market: Market;
15
+ private readonly _buys;
16
+ private readonly _sells;
17
+ private _initialized;
18
+ constructor(market: Market);
19
+ get symbol(): string;
20
+ get marketId(): number;
21
+ update(orders: Order[]): void;
22
+ private _add;
23
+ private _remove;
24
+ private _priceLevels;
25
+ hasValue(side: string): boolean;
26
+ bestPrice(side: string): number;
27
+ bestUnits(side: string): number;
28
+ bestBuyPrice(): number;
29
+ bestBuyUnits(): number;
30
+ bestSellPrice(): number;
31
+ bestSellUnits(): number;
32
+ /** Price levels sorted highest-first (best bid first). */
33
+ buyLevels(): [number, number][];
34
+ /** Price levels sorted lowest-first (best ask first). */
35
+ sellLevels(): [number, number][];
36
+ }
37
+ /**
38
+ * Container of OrderBook instances, one per market.
39
+ */
40
+ export declare class OrderBooks {
41
+ private readonly _books;
42
+ constructor(markets: Market[]);
43
+ update(orders: Order[]): void;
44
+ hasValue(marketId: number, side: string): boolean;
45
+ bestPrice(marketId: number, side: string): number;
46
+ collection(): OrderBook[];
47
+ get(marketId: number): OrderBook;
48
+ }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Order book maintained from WebSocket order events.
3
+ *
4
+ * Port of fm.orderbook (Python) / fm.OrderBook (Java).
5
+ */
6
+ import { isAvailable, isBuy, isCancel, isResting, isSplit, isSymbol } from "./order-utils.js";
7
+ /**
8
+ * Aggregated price-level order book for a single market.
9
+ *
10
+ * Updated incrementally from WebSocket ORDERS-UPDATE events.
11
+ * Buys are sorted highest-first (best bid), sells lowest-first (best ask).
12
+ */
13
+ export class OrderBook {
14
+ market;
15
+ _buys = new Map(); // price → units
16
+ _sells = new Map(); // price → units
17
+ _initialized = false;
18
+ constructor(market) {
19
+ this.market = market;
20
+ }
21
+ get symbol() {
22
+ return this.market.symbol;
23
+ }
24
+ get marketId() {
25
+ return this.market.id;
26
+ }
27
+ // -- update from WebSocket events ------------------------------------------
28
+ update(orders) {
29
+ let isSplitBatch = false;
30
+ for (const order of orders) {
31
+ if (!isSymbol(this.symbol, order))
32
+ continue;
33
+ const side = order.side;
34
+ const price = order.price;
35
+ const units = order.units;
36
+ // Add all available orders to the order book
37
+ if (isAvailable(order)) {
38
+ this._add(side, price, units);
39
+ continue;
40
+ }
41
+ // During initialisation, disregard all non-available orders
42
+ if (!this._initialized)
43
+ continue;
44
+ // Remove CANCEL orders
45
+ if (isCancel(order)) {
46
+ this._remove(side, price, units);
47
+ continue;
48
+ }
49
+ // Remove split orders from book
50
+ if (isSplit(order)) {
51
+ isSplitBatch = true;
52
+ this._remove(side, price, units);
53
+ continue;
54
+ }
55
+ // If not a split, remove consumed resting order
56
+ if (!isSplitBatch && isResting(orders, order)) {
57
+ this._remove(side, price, units);
58
+ continue;
59
+ }
60
+ }
61
+ if (!this._initialized) {
62
+ this._initialized = true;
63
+ }
64
+ }
65
+ _add(side, price, units) {
66
+ const levels = this._priceLevels(side);
67
+ levels.set(price, (levels.get(price) ?? 0) + units);
68
+ }
69
+ _remove(side, price, units) {
70
+ const levels = this._priceLevels(side);
71
+ const updated = (levels.get(price) ?? 0) - units;
72
+ if (updated < 1) {
73
+ levels.delete(price);
74
+ }
75
+ else {
76
+ levels.set(price, updated);
77
+ }
78
+ }
79
+ _priceLevels(side) {
80
+ return isBuy(side) ? this._buys : this._sells;
81
+ }
82
+ // -- query -----------------------------------------------------------------
83
+ hasValue(side) {
84
+ return this._priceLevels(side).size > 0;
85
+ }
86
+ bestPrice(side) {
87
+ const levels = this._priceLevels(side);
88
+ if (levels.size === 0)
89
+ return -1;
90
+ const prices = [...levels.keys()];
91
+ return isBuy(side) ? Math.max(...prices) : Math.min(...prices);
92
+ }
93
+ bestUnits(side) {
94
+ const levels = this._priceLevels(side);
95
+ if (levels.size === 0)
96
+ return -1;
97
+ const prices = [...levels.keys()];
98
+ const best = isBuy(side) ? Math.max(...prices) : Math.min(...prices);
99
+ return levels.get(best);
100
+ }
101
+ bestBuyPrice() {
102
+ return this.bestPrice("BUY");
103
+ }
104
+ bestBuyUnits() {
105
+ return this.bestUnits("BUY");
106
+ }
107
+ bestSellPrice() {
108
+ return this.bestPrice("SELL");
109
+ }
110
+ bestSellUnits() {
111
+ return this.bestUnits("SELL");
112
+ }
113
+ /** Price levels sorted highest-first (best bid first). */
114
+ buyLevels() {
115
+ return [...this._buys.entries()].sort((a, b) => b[0] - a[0]);
116
+ }
117
+ /** Price levels sorted lowest-first (best ask first). */
118
+ sellLevels() {
119
+ return [...this._sells.entries()].sort((a, b) => a[0] - b[0]);
120
+ }
121
+ }
122
+ /**
123
+ * Container of OrderBook instances, one per market.
124
+ */
125
+ export class OrderBooks {
126
+ _books = new Map();
127
+ constructor(markets) {
128
+ for (const m of markets) {
129
+ this._books.set(m.id, new OrderBook(m));
130
+ }
131
+ }
132
+ update(orders) {
133
+ for (const book of this._books.values()) {
134
+ book.update(orders);
135
+ }
136
+ }
137
+ hasValue(marketId, side) {
138
+ return this._books.get(marketId).hasValue(side);
139
+ }
140
+ bestPrice(marketId, side) {
141
+ return this._books.get(marketId).bestPrice(side);
142
+ }
143
+ collection() {
144
+ return [...this._books.values()];
145
+ }
146
+ get(marketId) {
147
+ return this._books.get(marketId);
148
+ }
149
+ }
150
+ //# sourceMappingURL=orderbook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orderbook.js","sourceRoot":"","sources":["../src/orderbook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
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 type { Holding, Order, Session, Version } from "./types.js";
8
+ export interface StompFrame {
9
+ command: string;
10
+ headers: Record<string, string>;
11
+ body: string;
12
+ }
13
+ export declare function encodeFrame(frame: StompFrame): string;
14
+ export declare function decodeFrame(raw: string): StompFrame;
15
+ export interface WsTransportError {
16
+ kind: "transport-error";
17
+ exception: Error;
18
+ }
19
+ export interface WsException {
20
+ kind: "ws-exception";
21
+ command: string;
22
+ headers: Record<string, string>;
23
+ body: string;
24
+ exception: Error;
25
+ }
26
+ export type FmEvent = Version | Session | Session[] | Holding | Order[] | WsTransportError | WsException;
27
+ export type EventCallback = (event: FmEvent) => void;
28
+ export declare class EventListener {
29
+ private readonly _wsUrl;
30
+ private readonly _bearerToken;
31
+ private readonly _marketplaceId;
32
+ private readonly _callback;
33
+ private readonly _clientDescription;
34
+ private readonly _parseHolding;
35
+ private readonly _parseOrder;
36
+ private _ws;
37
+ private _closed;
38
+ private _subscriptionCounter;
39
+ constructor(wsUrl: string, bearerToken: string, marketplaceId: number, callback: EventCallback, clientDescription: string, parseHolding: (data: Record<string, unknown>) => Holding, parseOrder: (data: Record<string, unknown>) => Order);
40
+ start(): Promise<void>;
41
+ reconnect(): Promise<void>;
42
+ close(): void;
43
+ private _connect;
44
+ private _disconnect;
45
+ private _nextId;
46
+ private _stompConnect;
47
+ private _subscribe;
48
+ private _receiveLoop;
49
+ }