ninjabook 0.1.7

A lightweight and high performance orderbook
Documentation
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collecting ninjabook\n",
      "  Downloading ninjabook-0.1.6-cp38-abi3-macosx_11_0_arm64.whl.metadata (429 bytes)\n",
      "Collecting tabulate\n",
      "  Using cached tabulate-0.9.0-py3-none-any.whl.metadata (34 kB)\n",
      "Downloading ninjabook-0.1.6-cp38-abi3-macosx_11_0_arm64.whl (217 kB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m217.2/217.2 kB\u001b[0m \u001b[31m6.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hUsing cached tabulate-0.9.0-py3-none-any.whl (35 kB)\n",
      "Installing collected packages: tabulate, ninjabook\n",
      "  Attempting uninstall: tabulate\n",
      "    Found existing installation: tabulate 0.9.0\n",
      "    Uninstalling tabulate-0.9.0:\n",
      "      Successfully uninstalled tabulate-0.9.0\n",
      "  Attempting uninstall: ninjabook\n",
      "    Found existing installation: ninjabook 0.1.5\n",
      "    Uninstalling ninjabook-0.1.5:\n",
      "      Successfully uninstalled ninjabook-0.1.5\n",
      "Successfully installed ninjabook-0.1.6 tabulate-0.9.0\n",
      "\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.3.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.0\u001b[0m\n",
      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n",
      "Note: you may need to restart the kernel to use updated packages.\n"
     ]
    }
   ],
   "source": [
    "%pip install ninjabook tabulate --force-reinstall"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Parsing raw data into `Event`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "300000"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import csv\n",
    "from ninjabook import Event\n",
    "\n",
    "events = []\n",
    "with open(\"../data/norm_book_data_300k.csv\", newline='') as csvfile:\n",
    "    reader = csv.DictReader(csvfile)\n",
    "    for row in reader:\n",
    "        event = Event(\n",
    "            timestamp= int(row['timestamp']),\n",
    "            seq=int(row['seq']),\n",
    "            is_trade=bool(row['is_trade']=='1'),\n",
    "            is_buy=bool(row['is_buy']=='1'),\n",
    "            price=float(row['price']),\n",
    "            size=float(row['size'])\n",
    "        )\n",
    "        events.append(event)\n",
    "\n",
    "len(events)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Ingesting `Events` and streaming BBO"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+------------------+--------+---------------+---------------+---------+---------------+---------------+\n",
      "|               ts |    seq |   best_bid_sz |   best_bid_px |     mid |   best_ask_px |   best_ask_sz |\n",
      "+==================+========+===============+===============+=========+===============+===============+\n",
      "| 1575161162310275 | 199955 |      0.019027 |       7490.55 | 7491.39 |       7492.22 |      0.204504 |\n",
      "+------------------+--------+---------------+---------------+---------+---------------+---------------+\n",
      "| 1575161162409739 | 199968 |      0.019027 |       7490.55 | 7491.35 |       7492.16 |      0.019353 |\n",
      "+------------------+--------+---------------+---------------+---------+---------------+---------------+\n",
      "| 1575161162509896 | 199980 |      0.019027 |       7490.55 | 7491.33 |       7492.1  |      0.3      |\n",
      "+------------------+--------+---------------+---------------+---------+---------------+---------------+\n",
      "| 1575161162610363 | 199987 |      0.019027 |       7490.55 | 7491.29 |       7492.03 |      0.211905 |\n",
      "+------------------+--------+---------------+---------------+---------+---------------+---------------+\n",
      "| 1575161162710305 | 199997 |      0.019027 |       7490.55 | 7491.27 |       7491.99 |      0.214587 |\n",
      "+------------------+--------+---------------+---------------+---------+---------------+---------------+\n"
     ]
    }
   ],
   "source": [
    "from ninjabook import Orderbook \n",
    "from tabulate import tabulate \n",
    "\n",
    "ob = Orderbook(0.01)\n",
    "\n",
    "data = []\n",
    "\n",
    "for event in events[:200_000]:\n",
    "    bbo = ob.process_stream_bbo(event)\n",
    "    if bbo != None:\n",
    "        best_bid_px = bbo[0].price if bbo[0] is not None else None\n",
    "        best_bid_sz = bbo[0].size if bbo[0] is not None else None\n",
    "        best_ask_px = bbo[1].price if bbo[1] is not None else None\n",
    "        best_ask_sz = bbo[1].size if bbo[1] is not None else None\n",
    "        mid = ob.midprice()\n",
    "        data.append([ob.last_updated, ob.last_sequence, best_bid_sz, best_bid_px, mid, best_ask_px, best_ask_sz])\n",
    "\n",
    "headers = [\"ts\", \"seq\", \"best_bid_sz\", \"best_bid_px\", \"mid\", \"best_ask_px\", \"best_ask_sz\"]\n",
    "\n",
    "print(tabulate(data[-5:], headers=headers, tablefmt=\"grid\"))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Processing `Events` and getting top 3 bids and asks"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "last sequence: 199999\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|   best_bid_sz |   best_bid_px |     mid |   best_ask_px |   best_ask_sz |\n",
      "+===============+===============+=========+===============+===============+\n",
      "|               |               |         |       7492.02 |      4        |\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|               |               |         |       7492.01 |      0.149845 |\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|               |               |         |       7491.99 |      0.214587 |\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|               |               | 7491.27 |               |               |\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|      0.019027 |       7490.55 |         |               |               |\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|      0.812102 |       7490.19 |         |               |               |\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|      0.401352 |       7490.1  |         |               |               |\n",
      "+---------------+---------------+---------+---------------+---------------+\n"
     ]
    }
   ],
   "source": [
    "from ninjabook import Orderbook\n",
    "from tabulate import tabulate \n",
    "\n",
    "ob = Orderbook(0.01)\n",
    "\n",
    "for event in events[:200_000]:\n",
    "    ob.process(event)\n",
    "    \n",
    "data = []\n",
    "\n",
    "for ask in sorted(ob.top_asks(3), key=lambda x: x.price, reverse=True):\n",
    "    data.append([None, None, None, ask.price, ask.size])\n",
    "    \n",
    "data.append([None, None, ob.midprice(), None, None])\n",
    "\n",
    "for bid in ob.top_bids(3):\n",
    "    data.append([bid.size, bid.price, None, None, None])\n",
    "    \n",
    "headers = [\"best_bid_sz\", \"best_bid_px\", \"mid\", \"best_ask_px\", \"best_ask_sz\"]\n",
    "\n",
    "print(\"last sequence:\", ob.last_sequence)\n",
    "print(tabulate(data, headers=headers, tablefmt=\"grid\"))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Processing raw events without using `Event`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "last sequence: 299999\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|   best_bid_sz |   best_bid_px |     mid |   best_ask_px |   best_ask_sz |\n",
      "+===============+===============+=========+===============+===============+\n",
      "|               |               |         |       7451.03 |       2.57563 |\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|               |               |         |       7451.02 |       1.11018 |\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|               |               |         |       7451.01 |       3.9983  |\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|               |               | 7450.36 |               |               |\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|      0.00279  |       7449.71 |         |               |               |\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|      2        |       7447.44 |         |               |               |\n",
      "+---------------+---------------+---------+---------------+---------------+\n",
      "|      0.531638 |       7447.43 |         |               |               |\n",
      "+---------------+---------------+---------+---------------+---------------+\n"
     ]
    }
   ],
   "source": [
    "from tabulate import tabulate \n",
    "\n",
    "from ninjabook import Orderbook\n",
    "\n",
    "\n",
    "ob = Orderbook(0.01) # tick_size = 0.01\n",
    "\n",
    "for raw in events:\n",
    "    ob.process_raw(\n",
    "        raw.timestamp, \n",
    "        raw.seq, \n",
    "        raw.is_trade, \n",
    "        raw.is_buy, \n",
    "        raw.price, \n",
    "        raw.size\n",
    "    )\n",
    "    \n",
    "data = []\n",
    "\n",
    "for ask in sorted(ob.top_asks(3), key=lambda x: x.price, reverse=True):\n",
    "    data.append([None, None, None, ask.price, ask.size])\n",
    "    \n",
    "data.append([None, None, ob.midprice(), None, None])\n",
    "\n",
    "for bid in ob.top_bids(3):\n",
    "    data.append([bid.size, bid.price, None, None, None])\n",
    "    \n",
    "headers = [\"best_bid_sz\", \"best_bid_px\", \"mid\", \"best_ask_px\", \"best_ask_sz\"]\n",
    "\n",
    "print(\"last sequence:\", ob.last_sequence)\n",
    "print(tabulate(data, headers=headers, tablefmt=\"grid\"))\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}