@@ -4,6 +4,7 @@ import { ERROR, ErrorCodes, ErrorMessages } from "../src/errors";
44import type { LimitOrder } from "../src/order" ;
55import { OrderBook } from "../src/orderbook" ;
66import type { OrderQueue } from "../src/orderqueue" ;
7+ import type { StopQueue } from "../src/stopqueue" ;
78import {
89 type ILimitOrder ,
910 type IProcessOrder ,
@@ -12,6 +13,7 @@ import {
1213 type JournalLog ,
1314 OrderType ,
1415 Side ,
16+ type StopOrder ,
1517 TimeInForce ,
1618} from "../src/types" ;
1719
@@ -1561,12 +1563,48 @@ void test("orderbook replayJournal test wrong journal", () => {
15611563} ) ;
15621564
15631565void test ( "orderbook test snapshot" , ( ) => {
1564- const ob = new OrderBook ( ) ;
1566+ const ob = new OrderBook ( { experimentalConditionalOrders : true } ) ;
1567+ const addStopOrder = (
1568+ side : Side ,
1569+ orderId : string ,
1570+ stopPrice : number ,
1571+ ) : void => {
1572+ ob . createOrder ( {
1573+ id : orderId ,
1574+ type : OrderType . STOP_LIMIT ,
1575+ side,
1576+ size : 10 ,
1577+ price : stopPrice ,
1578+ stopPrice,
1579+ timeInForce : TimeInForce . GTC ,
1580+ } ) ;
1581+ } ;
1582+ // Inizialize order book with some orders
15651583 addDepth ( ob , "" , 10 ) ;
1584+
1585+ // Add some stop orders
1586+ // Start with SELL side
1587+ addStopOrder ( Side . SELL , "sell-1" , 110 ) ;
1588+ addStopOrder ( Side . SELL , "sell-2" , 110 ) ; // Same price as before
1589+ addStopOrder ( Side . SELL , "sell-3" , 120 ) ;
1590+ addStopOrder ( Side . SELL , "sell-4" , 130 ) ;
1591+ addStopOrder ( Side . SELL , "sell-5" , 140 ) ;
1592+
1593+ // Test BUY side
1594+ addStopOrder ( Side . BUY , "buy-1" , 100 ) ;
1595+ addStopOrder ( Side . BUY , "buy-2" , 100 ) ; // Same price as before
1596+ addStopOrder ( Side . BUY , "buy-3" , 90 ) ;
1597+ addStopOrder ( Side . BUY , "buy-4" , 80 ) ;
1598+ addStopOrder ( Side . BUY , "buy-5" , 70 ) ;
1599+
15661600 const snapshot = ob . snapshot ( ) ;
15671601
15681602 assert . equal ( Array . isArray ( snapshot . asks ) , true ) ;
15691603 assert . equal ( Array . isArray ( snapshot . bids ) , true ) ;
1604+
1605+ assert . equal ( Array . isArray ( snapshot . stopBook . asks ) , true ) ;
1606+ assert . equal ( Array . isArray ( snapshot . stopBook . bids ) , true ) ;
1607+
15701608 assert . equal ( typeof snapshot . ts , "number" ) ;
15711609 snapshot . asks . forEach ( ( level ) => {
15721610 assert . equal ( typeof level . price , "number" ) ;
@@ -1591,15 +1629,84 @@ void test("orderbook test snapshot", () => {
15911629 assert . equal ( order . origSize , 10 ) ;
15921630 } ) ;
15931631 } ) ;
1632+
1633+ snapshot . stopBook . asks . forEach ( ( level ) => {
1634+ assert . equal ( typeof level . price , "number" ) ;
1635+ assert . equal ( Array . isArray ( level . orders ) , true ) ;
1636+ level . orders . forEach ( ( order ) => {
1637+ assert . equal ( typeof order . id , "string" ) ;
1638+ assert . equal ( order . type , OrderType . STOP_LIMIT ) ;
1639+ assert . equal ( order . side , Side . BUY ) ;
1640+ assert . equal ( order . size , 10 ) ;
1641+ // @ts -expect-error we know exists for IStopLimitOrder
1642+ assert . equal ( typeof order . price , "number" ) ;
1643+ assert . equal ( typeof order . stopPrice , "number" ) ;
1644+ } ) ;
1645+ } ) ;
1646+
1647+ snapshot . stopBook . bids . forEach ( ( level ) => {
1648+ assert . equal ( typeof level . price , "number" ) ;
1649+ assert . equal ( Array . isArray ( level . orders ) , true ) ;
1650+ level . orders . forEach ( ( order ) => {
1651+ assert . equal ( typeof order . id , "string" ) ;
1652+ assert . equal ( order . type , OrderType . STOP_LIMIT ) ;
1653+ assert . equal ( order . side , Side . BUY ) ;
1654+ assert . equal ( order . size , 10 ) ;
1655+ // @ts -expect-error we know exists for IStopLimitOrder
1656+ assert . equal ( typeof order . price , "number" ) ;
1657+ assert . equal ( typeof order . stopPrice , "number" ) ;
1658+ } ) ;
1659+ } ) ;
15941660} ) ;
15951661
15961662void test ( "orderbook restore from snapshot" , ( ) => {
15971663 // Create a new orderbook with 3 orders for price levels and make a snapshot
15981664 const journal : JournalLog [ ] = [ ] ;
1599- const ob = new OrderBook ( { enableJournaling : true } ) ;
1665+ const ob = new OrderBook ( {
1666+ enableJournaling : true ,
1667+ experimentalConditionalOrders : true ,
1668+ } ) ;
1669+
1670+ const addStopOrder = (
1671+ side : Side ,
1672+ orderId : string ,
1673+ stopPrice : number ,
1674+ ) : void => {
1675+ ob . createOrder ( {
1676+ id : orderId ,
1677+ type : OrderType . STOP_LIMIT ,
1678+ side,
1679+ size : 10 ,
1680+ price : stopPrice ,
1681+ stopPrice,
1682+ timeInForce : TimeInForce . GTC ,
1683+ } ) ;
1684+ } ;
1685+
1686+ // Inizialize order book with some orders
16001687 addDepth ( ob , "first-run-" , 10 , journal ) ;
1601- // addDepth(ob, "second-run-", 10, journal);
1602- // addDepth(ob, "third-run-", 10, journal);
1688+ addDepth ( ob , "second-run-" , 10 , journal ) ;
1689+ addDepth ( ob , "third-run-" , 10 , journal ) ;
1690+
1691+ // Add some stop orders
1692+ // Test BUY side
1693+ addStopOrder ( Side . BUY , "buy-1" , 100 ) ;
1694+ addStopOrder ( Side . BUY , "buy-2" , 100 ) ; // Same price as before
1695+ addStopOrder ( Side . BUY , "buy-3" , 90 ) ;
1696+ addStopOrder ( Side . BUY , "buy-4" , 80 ) ;
1697+ addStopOrder ( Side . BUY , "buy-5" , 70 ) ;
1698+
1699+ // Start with SELL side
1700+ const prevMarketprice = ob . marketPrice ;
1701+ // @ts -expect-error we should hack the marketPrice in order to let stop order to be executed
1702+ ob . _marketPrice = 150 ;
1703+ addStopOrder ( Side . SELL , "sell-1" , 110 ) ;
1704+ addStopOrder ( Side . SELL , "sell-2" , 110 ) ; // Same price as before
1705+ addStopOrder ( Side . SELL , "sell-3" , 120 ) ;
1706+ addStopOrder ( Side . SELL , "sell-4" , 130 ) ;
1707+ addStopOrder ( Side . SELL , "sell-5" , 140 ) ;
1708+ // @ts -expect-error restore marketPrice to the original market price
1709+ ob . _marketPrice = prevMarketprice ;
16031710
16041711 const snapshot = ob . snapshot ( ) ;
16051712 {
@@ -1608,6 +1715,30 @@ void test("orderbook restore from snapshot", () => {
16081715
16091716 assert . equal ( ob . toString ( ) , ob2 . toString ( ) ) ;
16101717 assert . deepStrictEqual ( ob . depth ( ) , ob2 . depth ( ) ) ;
1718+ assert . equal (
1719+ // @ts -expect-error these are private properties
1720+ ob . stopBook . bids
1721+ . priceTree ( )
1722+ . values . map ( ( queue ) => queue . toArray ( ) )
1723+ . join ( "," ) ,
1724+ // @ts -expect-error these are private properties
1725+ ob2 . stopBook . bids
1726+ . priceTree ( )
1727+ . values . map ( ( queue ) => queue . toArray ( ) )
1728+ . join ( "," ) ,
1729+ ) ;
1730+ assert . equal (
1731+ // @ts -expect-error these are private properties
1732+ ob . stopBook . asks
1733+ . priceTree ( )
1734+ . values . map ( ( queue ) => queue . toArray ( ) )
1735+ . join ( "," ) ,
1736+ // @ts -expect-error these are private properties
1737+ ob2 . stopBook . asks
1738+ . priceTree ( )
1739+ . values . map ( ( queue ) => queue . toArray ( ) )
1740+ . join ( "," ) ,
1741+ ) ;
16111742
16121743 // @ts -expect-error these are private properties
16131744 Object . entries ( ob . orders ) . forEach ( ( [ key , order ] ) => {
@@ -1661,10 +1792,42 @@ void test("orderbook restore from snapshot", () => {
16611792 ) ;
16621793 } ) ;
16631794
1795+ const prevStopBook : Record < number , StopOrder [ ] > = { } ;
1796+ const restoredStopBook : Record < number , StopOrder [ ] > = { } ;
1797+
1798+ // @ts -expect-error these are private properties
1799+ ob . stopBook . asks . priceTree ( ) . forEach ( ( price : number , level : StopQueue ) => {
1800+ prevStopBook [ price ] = level . toArray ( ) ;
1801+ } ) ;
1802+
1803+ // @ts -expect-error these are private properties
1804+ ob . stopBook . bids . priceTree ( ) . forEach ( ( price : number , level : StopQueue ) => {
1805+ prevStopBook [ price ] = level . toArray ( ) ;
1806+ } ) ;
1807+
1808+ // @ts -expect-error these are private properties
1809+ ob2 . stopBook . asks . priceTree ( ) . forEach ( ( price : number , level : StopQueue ) => {
1810+ restoredStopBook [ price ] = level . toArray ( ) ;
1811+ } ) ;
1812+
1813+ // @ts -expect-error these are private properties
1814+ ob2 . stopBook . bids . priceTree ( ) . forEach ( ( price : number , level : StopQueue ) => {
1815+ restoredStopBook [ price ] = level . toArray ( ) ;
1816+ } ) ;
1817+
1818+ Object . entries ( prevStopBook ) . forEach ( ( [ price , orders ] ) => {
1819+ assert . deepStrictEqual (
1820+ orders . map ( ( order ) => order . toObject ( ) ) ,
1821+ restoredStopBook [ price ] . map ( ( order ) => order . toObject ( ) ) ,
1822+ ) ;
1823+ } ) ;
1824+
16641825 // Compare also the snapshot from the original order book and the restored one
16651826 const snapshot2 = ob2 . snapshot ( ) ;
16661827 assert . deepStrictEqual ( snapshot . asks , snapshot2 . asks ) ;
16671828 assert . deepStrictEqual ( snapshot . bids , snapshot2 . bids ) ;
1829+ assert . deepStrictEqual ( snapshot . stopBook . asks , snapshot2 . stopBook . asks ) ;
1830+ assert . deepStrictEqual ( snapshot . stopBook . bids , snapshot2 . stopBook . bids ) ;
16681831 }
16691832
16701833 {
0 commit comments