order-book
Advanced tools
| ''' | ||
| Copyright (C) 2020-2024 Bryant Moscon - bmoscon@gmail.com | ||
| Please see the LICENSE file for the terms and conditions | ||
| associated with this software. | ||
| ''' | ||
| from decimal import Decimal | ||
| import pytest | ||
| from order_book import OrderBook | ||
| def test_minimum_depth_kraken(): | ||
| ob = OrderBook(max_depth=9, checksum_format='KRAKEN') | ||
| with pytest.raises(ValueError): | ||
| ob.checksum() | ||
| def test_kraken_checksum(): | ||
| # This checksum is from the kraken docs | ||
| ob = OrderBook(max_depth=10, checksum_format='KRAKEN') | ||
| asks = [ | ||
| ["0.05005", "0.00000500", "1582905487.684110"], | ||
| ["0.05010", "0.00000500", "1582905486.187983"], | ||
| ["0.05015", "0.00000500", "1582905484.480241"], | ||
| ["0.05020", "0.00000500", "1582905486.645658"], | ||
| ["0.05025", "0.00000500", "1582905486.859009"], | ||
| ["0.05030", "0.00000500", "1582905488.601486"], | ||
| ["0.05035", "0.00000500", "1582905488.357312"], | ||
| ["0.05040", "0.00000500", "1582905488.785484"], | ||
| ["0.05045", "0.00000500", "1582905485.302661"], | ||
| ["0.05050", "0.00000500", "1582905486.157467"] | ||
| ] | ||
| bids = [ | ||
| ["0.05000", "0.00000500", "1582905487.439814"], | ||
| ["0.04995", "0.00000500", "1582905485.119396"], | ||
| ["0.04990", "0.00000500", "1582905486.432052"], | ||
| ["0.04980", "0.00000500", "1582905480.609351"], | ||
| ["0.04975", "0.00000500", "1582905476.793880"], | ||
| ["0.04970", "0.00000500", "1582905486.767461"], | ||
| ["0.04965", "0.00000500", "1582905481.767528"], | ||
| ["0.04960", "0.00000500", "1582905487.378907"], | ||
| ["0.04955", "0.00000500", "1582905483.626664"], | ||
| ["0.04950", "0.00000500", "1582905488.509872"] | ||
| ] | ||
| for a in asks: | ||
| ob.asks[Decimal(a[0])] = Decimal(a[1]) | ||
| for b in bids: | ||
| ob.bids[Decimal(b[0])] = Decimal(b[1]) | ||
| assert ob.checksum() == 974947235 | ||
| # The following checksums are from recorded data | ||
| ob = OrderBook(max_depth=11, checksum_format='KRAKEN') | ||
| asks = [ | ||
| ["0.620000", "40.00000000"], | ||
| ["0.830000", "380.86649128"], | ||
| ["1.500000", "333.33333333"] | ||
| ] | ||
| bids = [ | ||
| ["0.520300", "3943.09454867"], | ||
| ["0.403200", "454.31671175"], | ||
| ["0.403100", "1522.68122054"], | ||
| ["0.403000", "43.31058726"], | ||
| ["0.353200", "49.38467346"], | ||
| ["0.261600", "66.67686034"], | ||
| ["0.111000", "99.09909910"], | ||
| ["0.110000", "909.09090909"], | ||
| ["0.000600", "3333.33333333"], | ||
| ["0.000400", "5000.00000000"], | ||
| ["0.000100", "1000000.00000000"] | ||
| ] | ||
| for a in asks: | ||
| ob.asks[Decimal(a[0])] = Decimal(a[1]) | ||
| for b in bids: | ||
| ob.bids[Decimal(b[0])] = Decimal(b[1]) | ||
| assert ob.checksum() == 577149452 | ||
| ob = OrderBook(max_depth=11, checksum_format='KRAKEN') | ||
| asks = [ | ||
| ["0.814900", "297.71298000"], | ||
| ["0.815000", "500.00000000"], | ||
| ["0.815100", "500.00399385"], | ||
| ["0.815200", "42.03000000"], | ||
| ["0.815300", "21.50000000"], | ||
| ["0.815400", "10.75000000"], | ||
| ["0.829900", "1442.34063708"], | ||
| ["0.830000", "380.86649128"], | ||
| ["1.500000", "333.33333333"] | ||
| ] | ||
| bids = [ | ||
| ["0.473400", "1284.67569684"], | ||
| ["0.441000", "40.00415721"], | ||
| ["0.342200", "51.43191116"], | ||
| ["0.261600", "66.92596839"], | ||
| ["0.111000", "99.09909910"], | ||
| ["0.110000", "909.09090909"], | ||
| ["0.000600", "3333.33333333"], | ||
| ["0.000400", "5000.00000000"], | ||
| ["0.000100", "1000000.00000000"] | ||
| ] | ||
| for a in asks: | ||
| ob.asks[Decimal(a[0])] = Decimal(a[1]) | ||
| for b in bids: | ||
| ob.bids[Decimal(b[0])] = Decimal(b[1]) | ||
| assert ob.checksum() == 2369158246 | ||
| ob = OrderBook(max_depth=11, checksum_format='KRAKEN') | ||
| asks = [ | ||
| ["0.000017680", "38663.54992198"], | ||
| ["0.000017690", "20623.74841086"], | ||
| ["0.000017700", "103797.62636430"], | ||
| ["0.000017710", "40745.97057228"], | ||
| ["0.000017720", "13296.04740856"], | ||
| ["0.000017730", "42078.86085768"], | ||
| ["0.000017740", "64.38065876"], | ||
| ["0.000017760", "1131.70427847"], | ||
| ["0.000017780", "43891.46024565"], | ||
| ["0.000017790", "43908.00000000"], | ||
| ["0.000017810", "0.00005437"] | ||
| ] | ||
| bids = [ | ||
| ["0.000017670", "0.00000048"], # small volume causes scientific notation | ||
| ["0.000017660", "50.29884341"], | ||
| ["0.000017650", "16958.37856622"], | ||
| ["0.000017640", "16735.08043085"], | ||
| ["0.000017630", "61895.21671233"], | ||
| ["0.000017620", "86958.66158205"], | ||
| ["0.000017610", "8564.64738216"], | ||
| ["0.000017600", "59539.93801826"], | ||
| ["0.000017580", "52578.63046424"], | ||
| ["0.000017570", "46812.60266777"], | ||
| ["0.000017560", "640.09877588"] | ||
| ] | ||
| for a in asks: | ||
| ob.asks[Decimal(a[0])] = Decimal(a[1]) | ||
| for b in bids: | ||
| ob.bids[Decimal(b[0])] = Decimal(b[1]) | ||
| assert ob.checksum() == 1611253991 | ||
| ob = OrderBook(checksum_format='KRAKEN') | ||
| assert ob.checksum() == 0 | ||
| def test_okx_checksum(): | ||
| ob = OrderBook(checksum_format='OKX') | ||
| asks = {Decimal("3366.8"): Decimal("9"), Decimal("3368"): Decimal("8"), Decimal("3372"): Decimal("8")} | ||
| bids = {Decimal("3366.1"): Decimal("7")} | ||
| ob.bids = bids | ||
| ob.asks = asks | ||
| assert ob.checksum() == 831078360 | ||
| ob = OrderBook(checksum_format='OKX') | ||
| asks = [ | ||
| ["28923.3", "1.87800235"], | ||
| ["28923.4", "0.04"], | ||
| ["28924.3", "0.06867412"], | ||
| ["28925.6", "0.09861686"], | ||
| ["28925.8", "0.16453656"], | ||
| ["28925.9", "2.23"], | ||
| ["28926", "0.32274814"], | ||
| ["28926.1", "0.6232534"], | ||
| ["28926.4", "1.04"], | ||
| ["28926.8", "0.01707781"], | ||
| ["28928.5", "0.07061975"], | ||
| ["28929", "0.144"], | ||
| ["28930.2", "0.1"], | ||
| ["28930.3", "6.40922866"], | ||
| ["28931.9", "0.54902396"], | ||
| ["28932", "0.17306693"], | ||
| ["28932.7", "2.5672"], | ||
| ["28932.8", "1.19528238"], | ||
| ["28932.9", "0.05"], | ||
| ["28933", "0.34194526"], | ||
| ["28933.5", "0.02319626"], | ||
| ["28933.6", "0.764"], | ||
| ["28933.7", "0.01"], | ||
| ["28934.4", "0.05"], | ||
| ["28935", "0.0115"], | ||
| ["28935.1", "0.48"], | ||
| ["28935.8", "0.00696447"], | ||
| ["28935.9", "0.144"], | ||
| ["28936", "0.12700417"], | ||
| ["28936.5", "1.58799999"] | ||
| ] | ||
| bids = [ | ||
| ["28923.2", "0.0000001"], | ||
| ["28923", "0.49101312"], | ||
| ["28922.4", "0.01251868"], | ||
| ["28921.2", "0.00020273"], | ||
| ["28920.9", "0.00009315"], | ||
| ["28920.3", "0.00008106"], | ||
| ["28920", "0.03448414"], | ||
| ["28919.6", "0.00002087"], | ||
| ["28919.3", "0.00026015"], | ||
| ["28919", "0.0000519"], | ||
| ["28917.7", "0.00014609"], | ||
| ["28916.7", "0.00002008"], | ||
| ["28915.9", "0.00009415"], | ||
| ["28915", "0.0454951"], | ||
| ["28914.6", "0.007"], | ||
| ["28914.3", "0.12709954"], | ||
| ["28913.7", "0.0060879"], | ||
| ["28913.6", "0.00342"], | ||
| ["28913.3", "0.00574477"], | ||
| ["28911.8", "0.00106132"], | ||
| ["28911.1", "0.00011083"], | ||
| ["28911", "0.00008173"], | ||
| ["28910", "0.0006918"], | ||
| ["28909.9", "0.06897"], | ||
| ["28909.8", "0.00975481"], | ||
| ["28909.6", "0.00001002"], | ||
| ["28909", "0.00134995"], | ||
| ["28908.5", "0.00796815"], | ||
| ["28908.4", "0.17308796"], | ||
| ["28908.1", "0.67728285"] | ||
| ] | ||
| for a in asks: | ||
| ob.asks[Decimal(a[0])] = Decimal(a[1]) | ||
| for b in bids: | ||
| ob.bids[Decimal(b[0])] = Decimal(b[1]) | ||
| assert ob.checksum() == 2399502091 | ||
| ob = OrderBook(checksum_format='OKX') | ||
| assert ob.checksum() == 0 | ||
| def test_bitget_checksum(): | ||
| ob = OrderBook(checksum_format='BITGET') | ||
| asks = [ | ||
| ["0.000000001461", "3422313485"], | ||
| ["0.000000001462", "174253432795"], | ||
| ["0.000000001465", "530000463264"], | ||
| ["0.000000001466", "799507026717"], | ||
| ["0.000000001467", "458580845176"], | ||
| ["0.000000001468", "1300000000000"], | ||
| ["0.000000001470", "29814639074"], | ||
| ["0.000000001471", "6904159343"], | ||
| ["0.000000001472", "71139049304"], | ||
| ["0.000000001473", "5735877536"], | ||
| ["0.000000001474", "3392130259"], | ||
| ["0.000000001475", "3389830509"], | ||
| ["0.000000001476", "81662587311"], | ||
| ["0.000000001477", "9142169664"], | ||
| ["0.000000001479", "87063042280"], | ||
| ["0.000000001480", "7035327151"], | ||
| ["0.000000001481", "193948520465"], | ||
| ["0.000000001482", "36857236128"], | ||
| ["0.000000001486", "3364737551"], | ||
| ["0.000000001487", "94365814068"], | ||
| ["0.000000001488", "7047935390"], | ||
| ["0.000000001489", "3357958362"], | ||
| ["0.000000001490", "23979201076"], | ||
| ["0.000000001491", "3353454059"], | ||
| ["0.000000001492", "3351206435"], | ||
| ["0.000000001493", "34245570920"], | ||
| ["0.000000001495", "3344481606"], | ||
| ["0.000000001496", "3342245990"], | ||
| ["0.000000001497", "5928111901"], | ||
| ["0.000000001498", "536314945995"] | ||
| ] | ||
| bids = [ | ||
| ["0.000000001452", "26041231119"], | ||
| ["0.000000001451", "765679503030"], | ||
| ["0.000000001450", "24988603767"], | ||
| ["0.000000001449", "1138718088876"], | ||
| ["0.000000001447", "12557585692"], | ||
| ["0.000000001446", "53377804919"], | ||
| ["0.000000001445", "3460207613"], | ||
| ["0.000000001444", "499764868141"], | ||
| ["0.000000001443", "523229389780"], | ||
| ["0.000000001442", "972284349540"], | ||
| ["0.000000001441", "3469812631"], | ||
| ["0.000000001440", "24023644819"], | ||
| ["0.000000001439", "34783252746"], | ||
| ["0.000000001438", "3477051461"], | ||
| ["0.000000001437", "96154818726"], | ||
| ["0.000000001436", "3481894151"], | ||
| ["0.000000001435", "436716489370"], | ||
| ["0.000000001433", "801993699520"], | ||
| ["0.000000001432", "1242648129244"], | ||
| ["0.000000001431", "79364670199"], | ||
| ["0.000000001429", "163983130634"], | ||
| ["0.000000001428", "68235008969"], | ||
| ["0.000000001426", "179767647586"], | ||
| ["0.000000001425", "1300000000000"], | ||
| ["0.000000001424", "1300000000000"], | ||
| ["0.000000001423", "75814709870"], | ||
| ["0.000000001421", "164996453397"], | ||
| ["0.000000001420", "16901408450"], | ||
| ["0.000000001419", "58875214144"], | ||
| ["0.000000001418", "4612402959"] | ||
| ] | ||
| for a in asks: | ||
| ob.asks[Decimal(a[0])] = Decimal(a[1]) | ||
| for b in bids: | ||
| ob.bids[Decimal(b[0])] = Decimal(b[1]) | ||
| assert ob.checksum() == 3720106698 | ||
| ob = OrderBook(checksum_format='BITGET') | ||
| assert ob.checksum() == 0 | ||
| def test_okcoin_checksum(): | ||
| ob = OrderBook(checksum_format='OKCOIN') | ||
| asks = {Decimal("3366.8"): Decimal("9"), Decimal("3368"): Decimal("8"), Decimal("3372"): Decimal("8")} | ||
| bids = {Decimal("3366.1"): Decimal("7")} | ||
| ob.bids = bids | ||
| ob.asks = asks | ||
| assert ob.checksum() == 831078360 | ||
| def test_ftx_checksum(): | ||
| ob = OrderBook(checksum_format='FTX') | ||
| asks = [ | ||
| ["0.003385", "142011.0"], | ||
| ["0.003395", "221850.0"], | ||
| ["0.0034", "120.0"], | ||
| ["0.003405", "149119.0"], | ||
| ["0.003415", "3.0"], | ||
| ["0.003425", "46851.0"], | ||
| ["0.00343", "162552.0"], | ||
| ["0.003445", "3.0"], | ||
| ["0.003455", "182323.0"], | ||
| ["0.003465", "123.0"], | ||
| ["0.003475", "171058.0"], | ||
| ["0.00348", "4.0"], | ||
| ["0.0035", "3.0"], | ||
| ["0.003515", "3.0"], | ||
| ["0.00352", "17.0"], | ||
| ["0.00353", "120.0"], | ||
| ["0.003535", "3.0"], | ||
| ["0.00355", "196293.0"], | ||
| ["0.003565", "168196.0"], | ||
| ["0.00357", "4.0"], | ||
| ["0.003585", "3.0"], | ||
| ["0.003595", "120.0"], | ||
| ["0.003605", "3.0"], | ||
| ["0.00361", "1.0"], | ||
| ["0.003615", "354598.0"], | ||
| ["0.00362", "3.0"], | ||
| ["0.003635", "5.0"], | ||
| ["0.00364", "181628.0"], | ||
| ["0.00365", "4.0"], | ||
| ["0.003655", "3.0"], | ||
| ["0.00366", "121.0"], | ||
| ["0.003675", "8.0"], | ||
| ["0.00368", "202178.0"], | ||
| ["0.00369", "3.0"], | ||
| ["0.0037", "179932.0"], | ||
| ["0.00371", "295577.0"], | ||
| ["0.003725", "123.0"], | ||
| ["0.003745", "3.0"], | ||
| ["0.00375", "1.0"], | ||
| ["0.00376", "3.0"], | ||
| ["0.003775", "208662.0"], | ||
| ["0.00378", "3.0"], | ||
| ["0.00379", "120.0"], | ||
| ["0.003795", "3.0"], | ||
| ["0.0038", "1.0"], | ||
| ["0.003815", "3.0"], | ||
| ["0.003825", "16.0"], | ||
| ["0.00383", "3.0"], | ||
| ["0.00385", "4.0"], | ||
| ["0.003855", "120.0"], | ||
| ["0.003865", "3.0"], | ||
| ["0.003885", "3.0"], | ||
| ["0.00389", "1.0"], | ||
| ["0.0039", "876.0"], | ||
| ["0.00392", "123.0"], | ||
| ["0.003935", "3.0"], | ||
| ["0.00394", "1.0"], | ||
| ["0.003955", "3.0"], | ||
| ["0.00397", "3.0"], | ||
| ["0.00398", "5.0"], | ||
| ["0.003985", "120.0"], | ||
| ["0.00399", "4.0"], | ||
| ["0.004005", "3.0"], | ||
| ["0.00402", "3.0"], | ||
| ["0.00403", "3.0"], | ||
| ["0.00405", "120.0"], | ||
| ["0.00406", "3.0"], | ||
| ["0.00409", "3.0"], | ||
| ["0.004115", "120.0"], | ||
| ["0.00412", "3.0"], | ||
| ["0.004135", "5.0"], | ||
| ["0.00414", "1764.0"], | ||
| ["0.00415", "3.0"], | ||
| ["0.00418", "123.0"], | ||
| ["0.00421", "3.0"], | ||
| ["0.00424", "3.0"], | ||
| ["0.004245", "120.0"], | ||
| ["0.00427", "3.0"], | ||
| ["0.00429", "16.0"], | ||
| ["0.0043", "3.0"], | ||
| ["0.00431", "120.0"], | ||
| ["0.00433", "3.0"], | ||
| ["0.00436", "3.0"], | ||
| ["0.004375", "120.0"], | ||
| ["0.00439", "3.0"], | ||
| ["0.00442", "3.0"], | ||
| ["0.00443", "147145.0"], | ||
| ["0.00444", "120.0"], | ||
| ["0.004445", "16.0"], | ||
| ["0.00445", "3.0"], | ||
| ["0.00448", "3.0"], | ||
| ["0.004505", "120.0"], | ||
| ["0.004515", "3.0"], | ||
| ["0.004545", "3.0"], | ||
| ["0.00457", "120.0"], | ||
| ["0.004575", "3.0"], | ||
| ["0.004595", "16.0"], | ||
| ["0.004605", "3.0"], | ||
| ["0.004635", "123.0"], | ||
| ["0.004665", "3.0"] | ||
| ] | ||
| bids = [ | ||
| ["0.00336", "3.0"], | ||
| ["0.00335", "39492.0"], | ||
| ["0.003345", "3.0"], | ||
| ["0.00334", "219821.0"], | ||
| ["0.00333", "17115.0"], | ||
| ["0.003325", "205654.0"], | ||
| ["0.003315", "8049.0"], | ||
| ["0.00331", "602.0"], | ||
| ["0.00329", "4.0"], | ||
| ["0.00328", "7.0"], | ||
| ["0.003275", "509455.0"], | ||
| ["0.00327", "120.0"], | ||
| ["0.003265", "148571.0"], | ||
| ["0.003255", "3.0"], | ||
| ["0.00324", "4.0"], | ||
| ["0.003235", "612.0"], | ||
| ["0.00322", "148150.0"], | ||
| ["0.003215", "169503.0"], | ||
| ["0.00321", "16.0"], | ||
| ["0.003205", "184421.0"], | ||
| ["0.0032", "1.0"], | ||
| ["0.003185", "3.0"], | ||
| ["0.00317", "3.0"], | ||
| ["0.00315", "8575.0"], | ||
| ["0.003145", "247853.0"], | ||
| ["0.003135", "3.0"], | ||
| ["0.00312", "3060.0"], | ||
| ["0.003115", "186021.0"], | ||
| ["0.00311", "1.0"], | ||
| ["0.003105", "229810.0"], | ||
| ["0.0031", "3.0"], | ||
| ["0.003095", "206811.0"], | ||
| ["0.00308", "3.0"], | ||
| ["0.003065", "3.0"], | ||
| ["0.003055", "16.0"], | ||
| ["0.003045", "3.0"], | ||
| ["0.00303", "3.0"], | ||
| ["0.00301", "288639.0"], | ||
| ["0.003", "272946.0"], | ||
| ["0.002995", "3.0"], | ||
| ["0.002975", "212459.0"], | ||
| ["0.002965", "244636.0"], | ||
| ["0.00296", "3.0"], | ||
| ["0.00294", "3.0"], | ||
| ["0.002925", "3.0"], | ||
| ["0.002905", "19.0"], | ||
| ["0.00289", "3.0"], | ||
| ["0.00287", "3.0"], | ||
| ["0.002855", "3.0"], | ||
| ["0.00284", "3.0"], | ||
| ["0.00282", "3.0"], | ||
| ["0.002805", "3.0"], | ||
| ["0.002785", "3.0"], | ||
| ["0.00277", "3.0"], | ||
| ["0.00275", "3.0"], | ||
| ["0.002735", "3.0"], | ||
| ["0.002715", "3.0"], | ||
| ["0.0027", "3.0"], | ||
| ["0.00268", "3.0"], | ||
| ["0.002665", "3.0"], | ||
| ["0.002645", "3.0"], | ||
| ["0.00263", "3.0"], | ||
| ["0.00261", "3.0"], | ||
| ["0.002595", "3.0"], | ||
| ["0.002575", "3.0"], | ||
| ["0.00256", "3.0"], | ||
| ["0.002555", "147658.0"], | ||
| ["0.00254", "3.0"], | ||
| ["0.002525", "3.0"], | ||
| ["0.002505", "3.0"], | ||
| ["0.00249", "3.0"], | ||
| ["0.00247", "3.0"], | ||
| ["0.002455", "3.0"], | ||
| ["0.002435", "3.0"], | ||
| ["0.00242", "3.0"], | ||
| ["0.0024", "3.0"], | ||
| ["0.002385", "3.0"], | ||
| ["0.002365", "3.0"], | ||
| ["0.00235", "3.0"], | ||
| ["0.00233", "3.0"], | ||
| ["0.002315", "3.0"], | ||
| ["0.0023", "3.0"], | ||
| ["0.002035", "3440.0"], | ||
| ["0.0015", "1333.0"], | ||
| ["0.0012", "5010.0"], | ||
| ["0.00033", "303030.0"], | ||
| ["0.00003", "371115.0"] | ||
| ] | ||
| for a in asks: | ||
| ob.asks[Decimal(a[0])] = Decimal(a[1]) | ||
| for b in bids: | ||
| ob.bids[Decimal(b[0])] = Decimal(b[1]) | ||
| assert ob.checksum() == 3169411573 | ||
| ob = OrderBook(checksum_format='FTX') | ||
| assert ob.checksum() == 0 | ||
| ''' | ||
| Copyright (C) 2020-2024 Bryant Moscon - bmoscon@gmail.com | ||
| Please see the LICENSE file for the terms and conditions | ||
| associated with this software. | ||
| ''' | ||
| from decimal import Decimal | ||
| import random | ||
| import pytest | ||
| import requests | ||
| from order_book import OrderBook | ||
| def populate_orderbook(): | ||
| ob = OrderBook() | ||
| data = requests.get("https://api.pro.coinbase.com/products/BTC-USD/book?level=2").json() | ||
| for side, d in data.items(): | ||
| if side == 'bids': | ||
| for price, size, _ in d: | ||
| ob.bids[Decimal(price)] = size | ||
| elif side == 'asks': | ||
| for price, size, _ in d: | ||
| ob.asks[Decimal(price)] = size | ||
| assert ob.bids.index(0)[0] < ob.asks.index(0)[0] | ||
| assert ob.bids.index(-1)[0] < ob.asks.index(-1)[0] | ||
| assert ob.bids.index(-1)[0] < ob.bids.index(0)[0] | ||
| assert ob.asks.index(-1)[0] > ob.asks.index(0)[0] | ||
| return ob | ||
| def test_orderbook(): | ||
| populate_orderbook() | ||
| def test_to_dict(): | ||
| ob = populate_orderbook() | ||
| data = ob.to_dict() | ||
| assert list(data['bid'].keys()) == list(ob.bids.keys()) | ||
| assert list(data['ask'].keys()) == list(ob.asks.keys()) | ||
| def test_orderbook_getitem(): | ||
| ob = OrderBook() | ||
| data = requests.get("https://api.pro.coinbase.com/products/BTC-USD/book?level=2").json() | ||
| for side, d in data.items(): | ||
| if side in {'bids', 'asks'}: | ||
| for price, size, _ in d: | ||
| ob[side][Decimal(price)] = size | ||
| assert ob.bids.index(0)[0] < ob.asks.index(0)[0] | ||
| assert ob.bids.index(-1)[0] < ob.asks.index(-1)[0] | ||
| assert ob.bids.index(-1)[0] < ob.bids.index(0)[0] | ||
| assert ob.asks.index(-1)[0] > ob.asks.index(0)[0] | ||
| with pytest.raises(KeyError): | ||
| # legal keys are BID, bid, BIDS, bids, ASK, ask, ASKS, asks | ||
| ob['invalid'][1] = 3 | ||
| def test_orderbook_init_errors(): | ||
| with pytest.raises(TypeError): | ||
| OrderBook('a') | ||
| with pytest.raises(TypeError): | ||
| OrderBook(blah=3) | ||
| with pytest.raises(TypeError): | ||
| OrderBook(max_depth='a') | ||
| def test_orderbook_init(): | ||
| ob = OrderBook(max_depth=10) | ||
| ob.bids = {val: val for val in range(20)} | ||
| ob.asks = {val: val for val in range(10, 30)} | ||
| assert len(ob) == 20 | ||
| def test_orderbook_len(): | ||
| random.seed() | ||
| bids = [] | ||
| asks = [] | ||
| for _ in range(500): | ||
| bids.append(random.uniform(0.0, 100000.0)) | ||
| bids = list(set(bids)) | ||
| for _ in range(500): | ||
| asks.append(random.uniform(0.0, 100000.0)) | ||
| asks = list(set(asks)) | ||
| ob = OrderBook() | ||
| for b in bids: | ||
| ob['BIDS'][b] = str(b) | ||
| for a in asks: | ||
| ob['ASKS'][a] = str(a) | ||
| assert len(ob) == len(asks) + len(bids) | ||
| def test_orderbook_keys(): | ||
| ob = OrderBook() | ||
| ob['bids'][1] = 1 | ||
| ob['BIDS'][1] = 2 | ||
| ob['bid'][1] = 3 | ||
| ob['BID'][1] = 4 | ||
| assert ob.bids.to_dict() == {1: 4} | ||
| assert ob.bid.to_dict() == {1: 4} | ||
| ob['asks'][1] = 1 | ||
| ob['ASKS'][1] = 2 | ||
| ob['ask'][1] = 3 | ||
| ob['ASK'][1] = 4 | ||
| assert ob.asks.to_dict() == {1: 4} | ||
| assert ob.ask.to_dict() == {1: 4} | ||
| def test_orderbook_setitem(): | ||
| ob = OrderBook() | ||
| data = requests.get("https://api.pro.coinbase.com/products/BTC-USD/book?level=2").json() | ||
| ob.bids = {Decimal(price): size for price, size, _ in data['bids']} | ||
| ob.asks = {Decimal(price): size for price, size, _ in data['asks']} | ||
| assert ob.bids.index(0)[0] < ob.asks.index(0)[0] | ||
| assert ob.bids.index(-1)[0] < ob.asks.index(-1)[0] | ||
| assert ob.bids.index(-1)[0] < ob.bids.index(0)[0] | ||
| assert ob.asks.index(-1)[0] > ob.asks.index(0)[0] | ||
| def test_orderbook_getitem_invalid(): | ||
| ob = OrderBook() | ||
| with pytest.raises(ValueError): | ||
| ob[1][1] = 'a' | ||
| def test_orderbook_setitem_invalid(): | ||
| ob = OrderBook() | ||
| with pytest.raises(ValueError): | ||
| ob[123] = {} | ||
| with pytest.raises(ValueError): | ||
| ob['invalid'] = {} | ||
| with pytest.raises(ValueError): | ||
| del ob['bids'] | ||
| with pytest.raises(ValueError): | ||
| ob['bids'] = 'a' | ||
| def test_checksum_raises(): | ||
| with pytest.raises(ValueError): | ||
| ob = OrderBook() | ||
| ob.checksum() | ||
| def test_l3_orderbook(): | ||
| ob = OrderBook() | ||
| raw_dict = {} | ||
| data = requests.get("https://api.pro.coinbase.com/products/BTC-USD/book?level=3").json() | ||
| for side, d in data.items(): | ||
| if side in {'bids', 'asks'}: | ||
| raw_dict[side] = {} | ||
| for price, size, orderid in d: | ||
| p = Decimal(price) | ||
| if p in ob[side]: | ||
| ob[side][p][orderid] = size | ||
| raw_dict[side][p][orderid] = size | ||
| assert p in ob[side] | ||
| assert len(ob[side][p]) > 1 | ||
| else: | ||
| ob[side][p] = {orderid: size} | ||
| raw_dict[side][p] = {orderid: size} | ||
| assert p in ob[side] | ||
| assert len(ob[side][p]) == 1 | ||
| assert ob.bids.index(0)[0] < ob.asks.index(0)[0] | ||
| assert ob.bids.index(-1)[0] < ob.asks.index(-1)[0] | ||
| assert ob.bids.index(-1)[0] < ob.bids.index(0)[0] | ||
| assert ob.asks.index(-1)[0] > ob.asks.index(0)[0] | ||
| ob_dict = ob.to_dict() | ||
| for side in raw_dict: | ||
| assert raw_dict[side] == ob[side].to_dict() == ob_dict[side[:-1]] | ||
| # test to_dict with type conversion | ||
| def convert(x): | ||
| if isinstance(x, Decimal): | ||
| return float(x) | ||
| if isinstance(x, dict): | ||
| return {k: float(v) for k, v in x.items()} | ||
| print("DOING") | ||
| ob_dict = ob.to_dict(to_type=convert) | ||
| for price in ob_dict['bid']: | ||
| assert isinstance(price, float) | ||
| for value in list(ob_dict['bid'][price].values()): | ||
| assert isinstance(value, float) | ||
| def test_del(): | ||
| ob = OrderBook() | ||
| ob.bids = {1: 1, 2: 2} | ||
| ob.asks = {5: 5, 6: 6, 7: 7} | ||
| assert len(ob.bids) == 2 | ||
| del ob.bids[1] | ||
| assert 1 not in ob.bids | ||
| assert 2 in ob.bids | ||
| assert len(ob.bids) == 1 | ||
| assert ob.bids.to_dict() == {2: 2} | ||
| def test_to_dict_types(): | ||
| input = { | ||
| '1.1': 2, | ||
| '3.3': 4, | ||
| '5.5': 6, | ||
| '7.7': 8 | ||
| } | ||
| ob = OrderBook() | ||
| ob.bids = input | ||
| ob.asks = input | ||
| data = ob.to_dict(from_type=str, to_type=float) | ||
| assert data['bid'] == {1.1: 2, 3.3: 4, 5.5: 6, 7.7: 8} | ||
| assert data['ask'] == {1.1: 2, 3.3: 4, 5.5: 6, 7.7: 8} |
| ''' | ||
| Copyright (C) 2020-2024 Bryant Moscon - bmoscon@gmail.com | ||
| Please see the LICENSE file for the terms and conditions | ||
| associated with this software. | ||
| ''' | ||
| from decimal import Decimal | ||
| import random | ||
| import pytest | ||
| from order_book import SortedDict | ||
| def test_ascending(): | ||
| s = SortedDict(ordering='ASC') | ||
| s[3] = "a" | ||
| s[2] = "b" | ||
| s[1] = "c" | ||
| assert s.keys() == (1, 2, 3) | ||
| def test_descending(): | ||
| s = SortedDict(ordering='DESC') | ||
| s[1] = "a" | ||
| s[3] = "b" | ||
| s[2] = "c" | ||
| assert s.keys() == (3, 2, 1) | ||
| def test_iteration(): | ||
| expected = (3, 2, 1) | ||
| index = None | ||
| s = SortedDict(ordering='DESC') | ||
| s[1] = "a" | ||
| s[3] = "b" | ||
| s[2] = "c" | ||
| for index, key in enumerate(s): | ||
| assert key == expected[index] | ||
| assert index == 2 | ||
| def test_index(): | ||
| s = SortedDict(ordering='DESC') | ||
| s[1] = "a" | ||
| s[3] = "b" | ||
| s[2] = "c" | ||
| assert s.index(0) == (3, "b") | ||
| assert s.index(1) == (2, "c") | ||
| assert s.index(2) == (1, "a") | ||
| assert s.index(-1) == (1, 'a') | ||
| assert s.index(-2) == (2, 'c') | ||
| assert s.index(-3) == (3, 'b') | ||
| with pytest.raises(IndexError): | ||
| assert s.index(3) == (2, "c") | ||
| with pytest.raises(IndexError): | ||
| assert s.index(4) == (2, "c") | ||
| def test_decimal(): | ||
| s = SortedDict(ordering='DESC') | ||
| s[Decimal('1.2')] = "a" | ||
| s[Decimal('1.5')] = "b" | ||
| s[Decimal('1.6')] = "c" | ||
| s[Decimal('1.7')] = "d" | ||
| assert len(s) == 4 | ||
| assert s.keys() == (Decimal('1.7'), Decimal('1.6'), Decimal('1.5'), Decimal('1.2')) | ||
| def test_random_data(): | ||
| random.seed() | ||
| values = [] | ||
| asc = SortedDict(ordering='ASC') | ||
| desc = SortedDict(ordering='DESC') | ||
| for _ in range(2000): | ||
| values.append(random.uniform(0.0, 100000.0)) | ||
| values = set(values) | ||
| for v in values: | ||
| asc[v] = str(v) | ||
| desc[v] = str(v) | ||
| previous = None | ||
| for key in asc: | ||
| assert key in values | ||
| assert str(key) == asc[key] | ||
| if previous: | ||
| assert previous < key | ||
| previous = key | ||
| previous = None | ||
| for key in desc: | ||
| assert key in values | ||
| assert str(key) == desc[key] | ||
| if previous: | ||
| assert previous > key | ||
| previous = key | ||
| def test_to_dict(): | ||
| random.seed() | ||
| values = [] | ||
| asc = SortedDict(ordering='ASC') | ||
| desc = SortedDict(ordering='DESC') | ||
| for _ in range(2000): | ||
| values.append(random.uniform(0.0, 100000.0)) | ||
| values = set(values) | ||
| for v in values: | ||
| asc[v] = str(v) | ||
| desc[v] = str(v) | ||
| d = asc.to_dict() | ||
| assert list(d.keys()) == list(asc.keys()) | ||
| assert sorted(d.keys()) == list(d.keys()) | ||
| previous = None | ||
| for key, _ in d.items(): | ||
| assert d[key] == asc[key] | ||
| if previous: | ||
| d[key] > previous | ||
| previous = d[key] | ||
| d = desc.to_dict() | ||
| assert list(d.keys()) == list(desc.keys()) | ||
| assert list(reversed(sorted(d.keys()))) == list(d.keys()) | ||
| previous = None | ||
| for key, val in d.items(): | ||
| assert d[key] == desc[key] | ||
| if previous: | ||
| d[key] < previous | ||
| previous = d[key] | ||
| def test_to_list(): | ||
| random.seed() | ||
| values = [] | ||
| asc = SortedDict(ordering='ASC') | ||
| desc = SortedDict(ordering='DESC') | ||
| for _ in range(2000): | ||
| values.append(random.uniform(0.0, 100000.0)) | ||
| values = set(values) | ||
| for v in values: | ||
| asc[v] = str(v) | ||
| desc[v] = str(v) | ||
| lst = asc.to_list() | ||
| _keys = list(list(zip(*lst))[0]) | ||
| assert _keys == list(asc.keys()) | ||
| assert sorted(_keys) == _keys | ||
| previous = None | ||
| for key, val in lst: | ||
| assert val == asc[key] | ||
| val = float(val) | ||
| if previous: | ||
| assert val > previous | ||
| previous = val | ||
| lst = desc.to_list() | ||
| _keys = list(list(zip(*lst))[0]) | ||
| assert _keys == list(desc.keys()) | ||
| assert list(reversed(sorted(_keys))) == _keys | ||
| previous = None | ||
| for key, val in lst: | ||
| assert val == desc[key] | ||
| val = float(val) | ||
| if previous: | ||
| assert val < previous | ||
| previous = val | ||
| def test_init_from_dict(): | ||
| with pytest.raises(TypeError): | ||
| asc = SortedDict("a", ordering='ASC') | ||
| with pytest.raises(TypeError): | ||
| asc = SortedDict({}, {}, ordering='ASC') | ||
| asc = SortedDict({4: 'a', 1: 'c', 3: 'f', 6: 'j', 9: 'z', 2: 'p'}, ordering='ASC') | ||
| assert asc.to_dict() == {1: 'c', 2: 'p', 3: 'f', 4: 'a', 6: 'j', 9: 'z'} | ||
| assert list(asc.keys()) == [1, 2, 3, 4, 6, 9] | ||
| desc = SortedDict({4: 'a', 1: 'c', 3: 'f', 6: 'j', 9: 'z', 2: 'p'}, ordering='DESC') | ||
| assert desc.to_dict() == {1: 'c', 2: 'p', 3: 'f', 4: 'a', 6: 'j', 9: 'z'} | ||
| assert list(desc.keys()) == [9, 6, 4, 3, 2, 1] | ||
| def test_invalid_ordering(): | ||
| with pytest.raises(ValueError): | ||
| SortedDict(ordering='D') | ||
| with pytest.raises(ValueError): | ||
| SortedDict(ordering=1) | ||
| def test_default_ordering(): | ||
| # default ordering is ascending | ||
| d = SortedDict() | ||
| d[3] = 'a' | ||
| d[2] = 'b' | ||
| d[1] = 'c' | ||
| assert list(d.keys()) == [1, 2, 3] | ||
| def test_illegal_index(): | ||
| d = SortedDict() | ||
| with pytest.raises(IndexError): | ||
| d.index(0) | ||
| with pytest.raises(TypeError): | ||
| d.index('a') | ||
| with pytest.raises(TypeError): | ||
| d.index() | ||
| def test_empty_keys(): | ||
| d = SortedDict() | ||
| assert d.keys() == () | ||
| def test_keys_reference_counting(): | ||
| d = SortedDict() | ||
| d[1] = 'a' | ||
| assert d.keys() == (1,) | ||
| d[2] = 'b' | ||
| assert d.keys() == (1, 2) | ||
| def test_invalid_key(): | ||
| d = SortedDict() | ||
| with pytest.raises(KeyError): | ||
| d[1] | ||
| with pytest.raises(KeyError): | ||
| del d[1] | ||
| def test_del(): | ||
| d = SortedDict() | ||
| d[3] = 'a' | ||
| d[2] = 'b' | ||
| d[1] = 'c' | ||
| del d[2] | ||
| assert d.keys() == (1, 3) | ||
| def test_iteration_noop(): | ||
| d = SortedDict() | ||
| counter = 0 | ||
| for _ in d: | ||
| counter += 1 | ||
| assert counter == 0 | ||
| def test_invalid_depth(): | ||
| with pytest.raises(ValueError): | ||
| SortedDict(max_depth=-1) | ||
| with pytest.raises(ValueError): | ||
| SortedDict(max_depth='A') | ||
| def test_invalid_truncate(): | ||
| with pytest.raises(ValueError): | ||
| SortedDict(truncate=10) | ||
| def test_depth_members(): | ||
| d = SortedDict(max_depth=10, truncate=True) | ||
| assert d.__max_depth == 10 | ||
| assert d.__truncate == 1 | ||
| e = SortedDict(max_depth=100, truncate=False) | ||
| assert e.__max_depth == 100 | ||
| assert e.__truncate == 0 | ||
| f = SortedDict() | ||
| assert f.__max_depth == 0 | ||
| assert f.__truncate == 0 | ||
| def test_depth(): | ||
| d = SortedDict({i: i for i in range(100)}, max_depth=10) | ||
| assert d.keys() == (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) | ||
| assert len(d) == 10 | ||
| assert len(d.to_dict()) == 10 | ||
| assert len(d.to_list()) == 10 | ||
| def test_depth_nontruncated(): | ||
| d = SortedDict({i: i for i in range(100)}, max_depth=10) | ||
| del d[5] | ||
| assert d.keys() == (0, 1, 2, 3, 4, 6, 7, 8, 9, 10) | ||
| def test_depth_truncated(): | ||
| d = SortedDict({i: i for i in range(100)}, max_depth=10) | ||
| d.truncate() | ||
| del d[5] | ||
| assert d.keys() == (0, 1, 2, 3, 4, 6, 7, 8, 9) | ||
| def test_depth_auto_truncate(): | ||
| d = SortedDict({i: i for i in range(100)}, truncate=True, max_depth=10) | ||
| del d[5] | ||
| assert d.keys() == (0, 1, 2, 3, 4, 6, 7, 8, 9) | ||
| d[1.1] = 0 | ||
| d[1.2] = 0 | ||
| d[1.3] = 0 | ||
| assert d.keys() == (0, 1, 1.1, 1.2, 1.3, 2, 3, 4, 6, 7) | ||
| def test_to_dict_types(): | ||
| input = { | ||
| 1: 2, | ||
| 3.3: 4, | ||
| Decimal('5.6'): 7.8, | ||
| 9: 11.11, | ||
| Decimal('1.3'): Decimal('3.3'), | ||
| 77.8: Decimal('19.9') | ||
| } | ||
| d = SortedDict(input) | ||
| assert d.to_dict() == input | ||
| assert d.to_dict(to_type=str) == {'1': '2', '3.3': '4', '5.6': '7.8', '9': '11.11', '1.3': '3.3', '77.8': '19.9'} | ||
| assert d.to_dict(from_type=str, to_type=float) == input | ||
| assert d.to_dict(to_type=float, from_type=Decimal) == {1: 2, 3.3: 4, 5.6: 7.8, 9: 11.11, 1.3: 3.3, 77.8: 19.9} |
+4
-0
| ## Changelog | ||
| ### 0.6.1 (2024-04-22) | ||
| * Update: to_list's behavior matches that of to_dict (respects max_depth, if set). | ||
| * Update: resolve build warnings on some compilers. | ||
| ### 0.6.0 (2022-10-19) | ||
@@ -4,0 +8,0 @@ * Update: Drop support for python 3.7 |
| Metadata-Version: 2.1 | ||
| Name: order-book | ||
| Version: 0.6.0 | ||
| Version: 0.6.1 | ||
| Summary: A fast orderbook implementation, in C, for Python | ||
@@ -10,3 +10,2 @@ Home-page: https://github.com/bmoscon/orderbook | ||
| Keywords: market data,trading | ||
| Platform: UNKNOWN | ||
| Classifier: Intended Audience :: Developers | ||
@@ -16,5 +15,6 @@ Classifier: Development Status :: 3 - Alpha | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 3.7 | ||
| Classifier: Programming Language :: Python :: 3.8 | ||
| Classifier: Programming Language :: Python :: 3.9 | ||
| Classifier: Programming Language :: Python :: 3.10 | ||
| Classifier: Programming Language :: Python :: 3.11 | ||
| Classifier: Programming Language :: Python :: 3.12 | ||
| Classifier: Programming Language :: Python :: 3 :: Only | ||
@@ -92,2 +92,10 @@ Classifier: Programming Language :: Python :: Implementation :: CPython | ||
| # Data can also be exported as an ordered list | ||
| # .to_list() returns a list of (price, size) tuples | ||
| print("Top 5 Asks") | ||
| print(ob.asks.to_list()[:5]) | ||
| print("\nTop 5 Bids") | ||
| print(ob.bids.to_list()[:5]) | ||
| ``` | ||
@@ -150,2 +158,6 @@ | ||
| ### 0.6.1 (2024-04-22) | ||
| * Update: to_list's behavior matches that of to_dict (respects max_depth, if set). | ||
| * Update: resolve build warnings on some compilers. | ||
| ### 0.6.0 (2022-10-19) | ||
@@ -224,3 +236,1 @@ * Update: Drop support for python 3.7 | ||
| * Initial Release | ||
@@ -15,2 +15,5 @@ CHANGES.md | ||
| orderbook/utils.c | ||
| orderbook/utils.h | ||
| orderbook/utils.h | ||
| tests/test_checksums.py | ||
| tests/test_orderbook.py | ||
| tests/test_sorteddict.py |
| /* | ||
| Copyright (C) 2020-2022 Bryant Moscon - bmoscon@gmail.com | ||
| Copyright (C) 2020-2024 Bryant Moscon - bmoscon@gmail.com | ||
@@ -543,3 +543,3 @@ Please see the LICENSE file for the terms and conditions | ||
| // default 'str' formatting is wrong when the value is in scientific notation | ||
| if (EXPECT(memchr(&data[startpos], (char) 'E', *pos - startpos), 0)) { | ||
| if (EXPECT((long)memchr(&data[startpos], (char) 'E', *pos - startpos), (long)0)) { | ||
| *pos = startpos; | ||
@@ -563,3 +563,3 @@ if (EXPECT(formatf_string_builder(pydata, data, pos), 0)) { | ||
| // default 'str' formatting is wrong when the value is less than 0.0001 or in scientific notation | ||
| if (EXPECT(!strncmp(&data[startpos], "0.0000", 6) || memchr(&data[startpos], (char) 'E', *pos - startpos), 0)) { | ||
| if (EXPECT(!strncmp((const char *)&data[startpos], "0.0000", 6) || memchr(&data[startpos], (char) 'E', *pos - startpos), 0)) { | ||
| *pos = startpos; | ||
@@ -566,0 +566,0 @@ if (EXPECT(floatstr_string_builder(pydata, data, pos), 0)) { |
| /* | ||
| Copyright (C) 2020-2022 Bryant Moscon - bmoscon@gmail.com | ||
| Copyright (C) 2020-2024 Bryant Moscon - bmoscon@gmail.com | ||
@@ -124,3 +124,3 @@ Please see the LICENSE file for the terms and conditions | ||
| .m_clear = order_book_clear, | ||
| .m_free = order_book_free, | ||
| .m_free = (void *)order_book_free, | ||
| }; | ||
@@ -127,0 +127,0 @@ |
| /* | ||
| Copyright (C) 2020-2022 Bryant Moscon - bmoscon@gmail.com | ||
| Copyright (C) 2020-2024 Bryant Moscon - bmoscon@gmail.com | ||
@@ -37,3 +37,3 @@ Please see the LICENSE file for the terms and conditions | ||
| self->ordering = INVALID_ORDERING; | ||
| self->ordering = INVALID_ORDERING; | ||
| // -1 means uninitalized | ||
@@ -343,15 +343,8 @@ self->iterator_index = -1; | ||
| PyObject* SortedDict_tolist(SortedDict *self, PyObject *args, PyObject *kwargs) | ||
| PyObject* SortedDict_tolist(SortedDict *self, PyObject *Py_UNUSED(ignored)) | ||
| { | ||
| static char* keywords[] = {"n_levels", NULL}; | ||
| int n_levels = -1; | ||
| if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", keywords, &n_levels)) { | ||
| return NULL; | ||
| } | ||
| int data_len = PyDict_Size(self->data); | ||
| // Set n_levels to data_len if n_levels is the default value | ||
| if (n_levels == -1 | n_levels > data_len) { | ||
| n_levels = data_len; | ||
| int len = PyDict_Size(self->data); | ||
| if ((self->depth > 0) && (self->depth < len)) { | ||
| len = self->depth; | ||
| } | ||
@@ -367,3 +360,3 @@ | ||
| PyObject *ret = PyList_New(n_levels); | ||
| PyObject *ret = PyList_New(len); | ||
| if (EXPECT(!ret, 0)) { | ||
@@ -373,3 +366,3 @@ return NULL; | ||
| for (int i = 0; i < n_levels; ++i) { | ||
| for (int i = 0; i < len; ++i) { | ||
| // new reference | ||
@@ -505,3 +498,3 @@ PyObject *key = PySequence_GetItem(self->keys, i); | ||
| self->iterator_index = -1; | ||
| return self; | ||
| return (PyObject *)self; | ||
| } | ||
@@ -508,0 +501,0 @@ |
| /* | ||
| Copyright (C) 2020-2022 Bryant Moscon - bmoscon@gmail.com | ||
| Copyright (C) 2020-2024 Bryant Moscon - bmoscon@gmail.com | ||
@@ -45,3 +45,3 @@ Please see the LICENSE file for the terms and conditions | ||
| PyObject* SortedDict_todict(SortedDict *self, PyObject *unused, PyObject *kwargs); | ||
| PyObject* SortedDict_tolist(SortedDict *self, PyObject *args, PyObject *kwargs); | ||
| PyObject* SortedDict_tolist(SortedDict *self, PyObject *Py_UNUSED(ignored)); | ||
| PyObject* SortedDict_truncate(SortedDict *self, PyObject *Py_UNUSED(ignored)); | ||
@@ -74,3 +74,3 @@ | ||
| {"to_dict", (PyCFunction) SortedDict_todict, METH_VARARGS | METH_KEYWORDS, "return a python dictionary, sorted by keys"}, | ||
| {"to_list", (PyCFunction) SortedDict_tolist, METH_VARARGS | METH_KEYWORDS, "return a list of key, value tuple with length specified in input argument. if no argument is passed or the argument is larger than length of self->data, return items with length of self->data."}, | ||
| {"to_list", (PyCFunction) SortedDict_tolist, METH_NOARGS, "return a list of key, value tuples."}, | ||
| {NULL} | ||
@@ -77,0 +77,0 @@ }; |
| /* | ||
| Copyright (C) 2020-2022 Bryant Moscon - bmoscon@gmail.com | ||
| Copyright (C) 2020-2024 Bryant Moscon - bmoscon@gmail.com | ||
@@ -4,0 +4,0 @@ Please see the LICENSE file for the terms and conditions |
| /* | ||
| Copyright (C) 2020-2022 Bryant Moscon - bmoscon@gmail.com | ||
| Copyright (C) 2020-2024 Bryant Moscon - bmoscon@gmail.com | ||
@@ -4,0 +4,0 @@ Please see the LICENSE file for the terms and conditions |
+16
-6
| Metadata-Version: 2.1 | ||
| Name: order_book | ||
| Version: 0.6.0 | ||
| Version: 0.6.1 | ||
| Summary: A fast orderbook implementation, in C, for Python | ||
@@ -10,3 +10,2 @@ Home-page: https://github.com/bmoscon/orderbook | ||
| Keywords: market data,trading | ||
| Platform: UNKNOWN | ||
| Classifier: Intended Audience :: Developers | ||
@@ -16,5 +15,6 @@ Classifier: Development Status :: 3 - Alpha | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 3.7 | ||
| Classifier: Programming Language :: Python :: 3.8 | ||
| Classifier: Programming Language :: Python :: 3.9 | ||
| Classifier: Programming Language :: Python :: 3.10 | ||
| Classifier: Programming Language :: Python :: 3.11 | ||
| Classifier: Programming Language :: Python :: 3.12 | ||
| Classifier: Programming Language :: Python :: 3 :: Only | ||
@@ -92,2 +92,10 @@ Classifier: Programming Language :: Python :: Implementation :: CPython | ||
| # Data can also be exported as an ordered list | ||
| # .to_list() returns a list of (price, size) tuples | ||
| print("Top 5 Asks") | ||
| print(ob.asks.to_list()[:5]) | ||
| print("\nTop 5 Bids") | ||
| print(ob.bids.to_list()[:5]) | ||
| ``` | ||
@@ -150,2 +158,6 @@ | ||
| ### 0.6.1 (2024-04-22) | ||
| * Update: to_list's behavior matches that of to_dict (respects max_depth, if set). | ||
| * Update: resolve build warnings on some compilers. | ||
| ### 0.6.0 (2022-10-19) | ||
@@ -224,3 +236,1 @@ * Update: Drop support for python 3.7 | ||
| * Initial Release | ||
+8
-0
@@ -65,2 +65,10 @@ # Orderbook | ||
| # Data can also be exported as an ordered list | ||
| # .to_list() returns a list of (price, size) tuples | ||
| print("Top 5 Asks") | ||
| print(ob.asks.to_list()[:5]) | ||
| print("\nTop 5 Bids") | ||
| print(ob.bids.to_list()[:5]) | ||
| ``` | ||
@@ -67,0 +75,0 @@ |
+5
-4
| ''' | ||
| Copyright (C) 2020-2022 Bryant Moscon - bmoscon@gmail.com | ||
| Copyright (C) 2020-2024 Bryant Moscon - bmoscon@gmail.com | ||
@@ -38,3 +38,3 @@ Please see the LICENSE file for the terms and conditions | ||
| name='order_book', | ||
| version='0.6.0', | ||
| version='0.6.1', | ||
| author="Bryant Moscon", | ||
@@ -57,5 +57,6 @@ author_email="bmoscon@gmail.com", | ||
| "Programming Language :: Python", | ||
| "Programming Language :: Python :: 3.7", | ||
| "Programming Language :: Python :: 3.8", | ||
| "Programming Language :: Python :: 3.9", | ||
| "Programming Language :: Python :: 3.10", | ||
| "Programming Language :: Python :: 3.11", | ||
| "Programming Language :: Python :: 3.12", | ||
| "Programming Language :: Python :: 3 :: Only", | ||
@@ -62,0 +63,0 @@ "Programming Language :: Python :: Implementation :: CPython", |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
134816
30.8%20
17.65%978
1646.43%