[
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.ipynb_checkpoints\n__pycache__\n*.csv\n"
  },
  {
    "path": ".idea/.name",
    "content": "BSE.py"
  },
  {
    "path": ".idea/BristolStockExchange.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"PYTHON_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\">\n    <content url=\"file://$MODULE_DIR$\">\n      <excludeFolder url=\"file://$MODULE_DIR$/venv\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": ".idea/inspectionProfiles/profiles_settings.xml",
    "content": "<component name=\"InspectionProjectProfileManager\">\n  <settings>\n    <option name=\"USE_PROJECT_PROFILE\" value=\"false\" />\n    <version value=\"1.0\" />\n  </settings>\n</component>"
  },
  {
    "path": ".idea/misc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectRootManager\" version=\"2\" project-jdk-name=\"Python 3.9 (BristolStockExchange)\" project-jdk-type=\"Python SDK\" />\n</project>"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/BristolStockExchange.iml\" filepath=\"$PROJECT_DIR$/.idea/BristolStockExchange.iml\" />\n    </modules>\n  </component>\n</project>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"$PROJECT_DIR$\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/workspace.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"AutoImportSettings\">\n    <option name=\"autoReloadType\" value=\"SELECTIVE\" />\n  </component>\n  <component name=\"ChangeListManager\">\n    <list default=\"true\" id=\"495f364a-cc51-4bd6-acc7-893e289ebda4\" name=\"Changes\" comment=\"\" />\n    <option name=\"SHOW_DIALOG\" value=\"false\" />\n    <option name=\"HIGHLIGHT_CONFLICTS\" value=\"true\" />\n    <option name=\"HIGHLIGHT_NON_ACTIVE_CHANGELIST\" value=\"false\" />\n    <option name=\"LAST_RESOLUTION\" value=\"IGNORE\" />\n  </component>\n  <component name=\"Git.Settings\">\n    <option name=\"RECENT_GIT_ROOT_PATH\" value=\"$PROJECT_DIR$\" />\n  </component>\n  <component name=\"MarkdownSettingsMigration\">\n    <option name=\"stateVersion\" value=\"1\" />\n  </component>\n  <component name=\"ProjectId\" id=\"2GFqCJUSQoIJ8lkeULZPqC2YzBe\" />\n  <component name=\"ProjectLevelVcsManager\" settingsEditedManually=\"true\" />\n  <component name=\"ProjectViewState\">\n    <option name=\"hideEmptyMiddlePackages\" value=\"true\" />\n    <option name=\"showLibraryContents\" value=\"true\" />\n  </component>\n<<<<<<< HEAD\n  <component name=\"PropertiesComponent\">{\n  &quot;keyToString&quot;: {\n    &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,\n    &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,\n    &quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,\n    &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,\n    &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,\n    &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,\n    &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,\n    &quot;settings.editor.selected.configurable&quot;: &quot;org.jetbrains.plugins.notebooks.jupyter.connections.configuration.JupyterServerConfigurable&quot;\n=======\n\n  <component name=\"PropertiesComponent\"><![CDATA[{\n  \"keyToString\": {\n    \"RunOnceActivity.OpenProjectViewOnStart\": \"true\",\n    \"RunOnceActivity.ShowReadmeOnStart\": \"true\",\n    \"WebServerToolWindowFactoryState\": \"false\",\n    \"node.js.detected.package.eslint\": \"true\",\n    \"node.js.detected.package.tslint\": \"true\",\n    \"node.js.selected.package.eslint\": \"(autodetect)\",\n    \"node.js.selected.package.tslint\": \"(autodetect)\",\n    \"settings.editor.selected.configurable\": \"org.jetbrains.plugins.notebooks.jupyter.connections.configuration.JupyterServerConfigurable\"\n>>>>>>> fae9de5d8fd858b6ca07f57614c782d21246beaa\n  }\n}</component>\n  <component name=\"RunManager\">\n    <configuration name=\"BSE\" type=\"PythonConfigurationType\" factoryName=\"Python\" nameIsGenerated=\"true\">\n      <module name=\"BristolStockExchange\" />\n      <option name=\"INTERPRETER_OPTIONS\" value=\"\" />\n      <option name=\"PARENT_ENVS\" value=\"true\" />\n      <envs>\n        <env name=\"PYTHONUNBUFFERED\" value=\"1\" />\n      </envs>\n      <option name=\"SDK_HOME\" value=\"/usr/local/bin/python3.10\" />\n      <option name=\"WORKING_DIRECTORY\" value=\"$PROJECT_DIR$\" />\n      <option name=\"IS_MODULE_SDK\" value=\"false\" />\n      <option name=\"ADD_CONTENT_ROOTS\" value=\"true\" />\n      <option name=\"ADD_SOURCE_ROOTS\" value=\"true\" />\n      <EXTENSION ID=\"PythonCoverageRunConfigurationExtension\" runner=\"coverage.py\" />\n      <option name=\"SCRIPT_NAME\" value=\"$PROJECT_DIR$/BSE.py\" />\n      <option name=\"PARAMETERS\" value=\"\" />\n      <option name=\"SHOW_COMMAND_LINE\" value=\"false\" />\n      <option name=\"EMULATE_TERMINAL\" value=\"false\" />\n      <option name=\"MODULE_MODE\" value=\"false\" />\n      <option name=\"REDIRECT_INPUT\" value=\"false\" />\n      <option name=\"INPUT_FILE\" value=\"\" />\n      <method v=\"2\" />\n    </configuration>\n  </component>\n  <component name=\"SpellCheckerSettings\" RuntimeDictionaries=\"0\" Folders=\"0\" CustomDictionaries=\"0\" DefaultDictionary=\"application-level\" UseSingleDictionary=\"true\" transferred=\"true\" />\n  <component name=\"TaskManager\">\n    <task active=\"true\" id=\"Default\" summary=\"Default task\">\n      <changelist id=\"495f364a-cc51-4bd6-acc7-893e289ebda4\" name=\"Changes\" comment=\"\" />\n      <created>1665994552377</created>\n      <option name=\"number\" value=\"Default\" />\n      <option name=\"presentableId\" value=\"Default\" />\n      <updated>1665994552377</updated>\n      <workItem from=\"1665994563147\" duration=\"8237000\" />\n      <workItem from=\"1698491854751\" duration=\"728000\" />\n\n    </task>\n    <servers />\n  </component>\n  <component name=\"TypeScriptGeneratedFilesManager\">\n    <option name=\"version\" value=\"3\" />\n  </component>\n  <component name=\"Vcs.Log.Tabs.Properties\">\n    <option name=\"TAB_STATES\">\n      <map>\n        <entry key=\"MAIN\">\n          <value>\n            <State />\n          </value>\n        </entry>\n      </map>\n    </option>\n  </component>\n  <component name=\"com.intellij.coverage.CoverageDataManagerImpl\">\n    <SUITE FILE_PATH=\"coverage/BristolStockExchange$BSE.coverage\" NAME=\"BSE Coverage Results\" MODIFIED=\"1698488749188\" SOURCE_PROVIDER=\"com.intellij.coverage.DefaultCoverageFileProvider\" RUNNER=\"coverage.py\" COVERAGE_BY_TEST_ENABLED=\"true\" COVERAGE_TRACING_ENABLED=\"false\" WORKING_DIRECTORY=\"$PROJECT_DIR$\" />\n  </component>\n</project>"
  },
  {
    "path": "BSE.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# BSE: The Bristol Stock Exchange\n#\n# Version 1.91: November 2024 fixed PT1 + PT2 parameter passing/unpacking\n# Version 1.9: March 2024 added PT1+PT2, plus all the docstrings.\n# Version 1.8; March 2023 added ZIPSH\n# Version 1.7; September 2022 added PRDE\n# Version 1.6; September 2021 added PRSH\n# Version 1.5; 02 Jan 2021 -- was meant to be the final version before switch to BSE2.x, but that didn't happen :-)\n# Version 1.4; 26 Oct 2020 -- change to Python 3.x\n# Version 1.3; July 21st, 2018 (Python 2.x)\n# Version 1.2; November 17th, 2012 (Python 2.x)\n#\n# Copyright (c) 2012-2024, Dave Cliff\n#\n#\n# ------------------------\n#\n# MIT Open-Source License:\n# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and\n# associated documentation files (the \"Software\"), to deal in the Software without restriction,\n# including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\n# and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,\n# subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in all copies or substantial\n# portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT\n# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n#\n# ------------------------\n#\n#\n#\n# BSE is a very simple simulation of automated execution traders\n# operating on a very simple model of a limit order book (LOB) exchange's matching engine.\n#\n# major simplifications in this version:\n#       (a) only one financial instrument being traded\n#       (b) traders can only trade contracts of size 1\n#       (c) each trader can have max of one order per single orderbook.\n#       (d) traders can replace/overwrite earlier orders, and/or can cancel, with no fee/penalty imposed for doing so\n#       (d) simply processes each order in sequence and republishes LOB to all traders\n#           => no issues with exchange processing latency/delays or simultaneously issued orders.\n#\n# NB this code has been written to be readable/intelligible, not efficient!\n\nimport sys\nimport math\nimport random\nimport os\nimport time as chrono\nimport csv\nfrom datetime import datetime\n\n# a bunch of system constants (globals)\nbse_sys_minprice = 1                    # minimum price in the system, in cents/pennies\nbse_sys_maxprice = 500                  # maximum price in the system, in cents/pennies\n# ticksize should be a param of an exchange (so different exchanges can have different ticksizes)\nticksize = 1  # minimum change in price, in cents/pennies\n\n\n# an Order/quote has a trader id, a type (buy/sell) price, quantity, timestamp, and unique i.d.\nclass Order:\n    \"\"\"\n    An Order: this is used both for client-orders from exogenous customers to the robot traders acting as sales traders,\n    and for the trader-orders (aka quotes) sent by the robot traders to the BSE exchange.\n    In both use-cases, an order has a trader-i.d., a type (buy/sell), price, quantity, timestamp, and unique quote-i.d.\n    \"\"\"\n\n    def __init__(self, tid, otype, price, qty, time, qid):\n        self.tid = tid  # trader i.d.\n        self.otype = otype  # order type\n        self.price = price  # price\n        self.qty = qty  # quantity\n        self.time = time  # timestamp\n        self.qid = qid  # quote i.d. (unique to each quote)\n\n    def __str__(self):\n        return '[%s %s P=%03d Q=%s T=%5.2f QID:%d]' % \\\n               (self.tid, self.otype, self.price, self.qty, self.time, self.qid)\n\n\nclass OrderbookHalf:\n    \"\"\"\n    OrderbookHalf is one side of the book: a list of bids or a list of asks, each sorted best-price-first,\n    and with orders at the same price arranged by arrival time (oldest first) for time-priority processing.\n    \"\"\"\n\n    def __init__(self, booktype, worstprice):\n        \"\"\"\n        Create one side of the LOB\n        :param booktype: specifies bid or ask side of the LOB.\n        :param worstprice: the initial value of the worst price currently showing on the LOB.\n        \"\"\"\n        # booktype: bids or asks?\n        self.booktype = booktype\n        # dictionary of orders received, indexed by Trader ID\n        self.orders = {}\n        # limit order book, dictionary indexed by price, with order info\n        self.lob = {}\n        # anonymized LOB, lists, with only price/qty info\n        self.lob_anon = []\n        # summary stats\n        self.best_price = None\n        self.best_tid = None\n        self.worstprice = worstprice\n        self.session_extreme = None    # most extreme price quoted in this session\n        self.n_orders = 0  # how many orders?\n        self.lob_depth = 0  # how many different prices on lob?\n\n    def anonymize_lob(self):\n        \"\"\"\n        anonymize a lob, strip out order details, format as a sorted list\n        NB for asks, the sorting should be reversed\n        :return: <nothing>\n        \"\"\"\n        self.lob_anon = []\n        for price in sorted(self.lob):\n            qty = self.lob[price][0]\n            self.lob_anon.append([price, qty])\n\n    def build_lob(self):\n        \"\"\"\n        Take a list of orders and build a limit-order-book (lob) from it\n        NB the exchange needs to know arrival times and trader-id associated with each order\n        also builds anonymized version (just price/quantity, sorted, as a list) for publishing to traders\n        :return: lob as a dictionary (i.e., unsorted)\n        \"\"\"\n        lob_verbose = False\n        self.lob = {}\n        for tid in self.orders:\n            order = self.orders.get(tid)\n            price = order.price\n            if price in self.lob:\n                # update existing entry\n                qty = self.lob[price][0]\n                orderlist = self.lob[price][1]\n                orderlist.append([order.time, order.qty, order.tid, order.qid])\n                self.lob[price] = [qty + order.qty, orderlist]\n            else:\n                # create a new dictionary entry\n                self.lob[price] = [order.qty, [[order.time, order.qty, order.tid, order.qid]]]\n        # create anonymized version\n        self.anonymize_lob()\n        # record best price and associated trader-id\n        if len(self.lob) > 0:\n            if self.booktype == 'Bid':\n                self.best_price = self.lob_anon[-1][0]\n            else:\n                self.best_price = self.lob_anon[0][0]\n            self.best_tid = self.lob[self.best_price][1][0][2]\n        else:\n            self.best_price = None\n            self.best_tid = None\n\n        if lob_verbose:\n            print(self.lob)\n\n    def book_add(self, order):\n        \"\"\"\n        Add order to the dictionary holding the list of orders for one side of the LOB.\n        Either overwrites old order from this trader\n            or dynamically creates new entry in the dictionary\n            so there is a max of one order per trader per list\n        checks whether length or order list has changed, to distinguish addition/overwrite\n        :param order: the order to be added to the book\n        :return: character-string indicating whether order-book was added to or overwritten.\n        \"\"\"\n\n        # if this is an ask, does the price set a new extreme-high record?\n        if (self.booktype == 'Ask') and ((self.session_extreme is None) or (order.price > self.session_extreme)):\n            self.session_extreme = int(order.price)\n\n        # add the order to the book\n        n_orders = self.n_orders\n        self.orders[order.tid] = order\n        self.n_orders = len(self.orders)\n        self.build_lob()\n        # print('book_add < %s %s' % (order, self.orders))\n        if n_orders != self.n_orders:\n            return 'Addition'\n        else:\n            return 'Overwrite'\n\n    def book_del(self, order):\n        \"\"\"\n        Delete order from the dictionary holding the orders for one half of the book.\n        Assumes max of one order per trader per list.\n        Checks that the Trader ID does actually exist in the dict before deletion.\n        :param order: the order to be deleted.\n        :return: <nothing>\n        \"\"\"\n        if self.orders.get(order.tid) is not None:\n            del (self.orders[order.tid])\n            self.n_orders = len(self.orders)\n            self.build_lob()\n        # print('book_del %s', self.orders)\n\n    def delete_best(self):\n        \"\"\"\n        When the best bid/ask has been hit/lifted, delete it from the book.\n        :return: TraderID of the deleted order is return-value, as counterparty to the trade.\n        \"\"\"\n\n        best_price_orders = self.lob[self.best_price]\n        best_price_qty = best_price_orders[0]\n        best_price_counterparty = best_price_orders[1][0][2]\n        if best_price_qty == 1:\n            # here the order deletes the best price\n            del (self.lob[self.best_price])\n            del (self.orders[best_price_counterparty])\n            self.n_orders = self.n_orders - 1\n            if self.n_orders > 0:\n                if self.booktype == 'Bid':\n                    self.best_price = max(self.lob.keys())\n                else:\n                    self.best_price = min(self.lob.keys())\n                self.lob_depth = len(self.lob.keys())\n            else:\n                self.best_price = self.worstprice\n                self.lob_depth = 0\n        else:\n            # best_bid_qty>1 so the order decrements the quantity of the best bid\n            # update the lob with the decremented order data\n            self.lob[self.best_price] = [best_price_qty - 1, best_price_orders[1][1:]]\n\n            # update the bid list: counterparty's bid has been deleted\n            del (self.orders[best_price_counterparty])\n            self.n_orders = self.n_orders - 1\n        self.build_lob()\n        return best_price_counterparty\n\n\nclass Orderbook(OrderbookHalf):\n    \"\"\" Orderbook for a single tradeable asset: list of bids and list of asks \"\"\"\n\n    def __init__(self):\n        \"\"\"Construct a new orderbook\"\"\"\n\n        self.bids = OrderbookHalf('Bid', bse_sys_minprice)\n        self.asks = OrderbookHalf('Ask', bse_sys_maxprice)\n        self.tape = []\n        self.tape_length = 10000    # max events on in-memory tape (older events can be written to tape_dump file)\n        self.quote_id = 0           # unique ID code for each quote accepted onto the book\n        self.lob_string = ''        # character-string linearization of public lob items with nonzero quantities\n\n\nclass Exchange(Orderbook):\n    \"\"\"  Exchange's matching engine and limit order book\"\"\"\n\n    def add_order(self, order, vrbs):\n        \"\"\"\n        add an order to the exchange -- either match with a counterparty order on LOB, or add to LOB.\n        :param order: the order to be added to the LOB\n        :param vrbs: verbosity: if True, print a running commentary; if False, stay silent.\n        :return: [order.qid, response] -- order.qid is the order's unique quote i.d., response is 'Overwrite'|'Addition'\n        \"\"\"\n        # add a quote/order to the exchange and update all internal records; return unique i.d.\n        order.qid = self.quote_id\n        self.quote_id = order.qid + 1\n        if vrbs:\n            print('add_order QID=%d self.quote.id=%d' % (order.qid, self.quote_id))\n        if order.otype == 'Bid':\n            response = self.bids.book_add(order)\n            best_price = self.bids.lob_anon[-1][0]\n            self.bids.best_price = best_price\n            self.bids.best_tid = self.bids.lob[best_price][1][0][2]\n        else:\n            response = self.asks.book_add(order)\n            best_price = self.asks.lob_anon[0][0]\n            self.asks.best_price = best_price\n            self.asks.best_tid = self.asks.lob[best_price][1][0][2]\n        return [order.qid, response]\n\n    def del_order(self, time, order, tape_file, vrbs):\n        \"\"\"\n        Delete an order from the exchange.\n        :param time: the current time.\n        :param order: the order to be deleted from the LOB.\n        :param tape_file: if not None, write details of the cancellation to the tape file.\n        :param vrbs: verbosity: if True, print a running commentary; if False, stay silent.\n        :return: <nothing>\n        \"\"\"\n        # delete a trader's quote/order from the exchange, update all internal records\n        if vrbs:\n            print('del_order QID=%d' % order.qid)\n        if order.otype == 'Bid':\n            self.bids.book_del(order)\n            if self.bids.n_orders > 0:\n                best_price = self.bids.lob_anon[-1][0]\n                self.bids.best_price = best_price\n                self.bids.best_tid = self.bids.lob[best_price][1][0][2]\n            else:  # this side of book is empty\n                self.bids.best_price = None\n                self.bids.best_tid = None\n            cancel_record = {'type': 'Cancel', 'time': time, 'order': order}\n            if tape_file is not None:\n                tape_file.write('CAN, %f, %d, Bid, %d\\n' % (time, order.qid, order.price))\n            self.tape.append(cancel_record)\n            # right-truncate the tape so that it keeps only the most recent items\n            self.tape = self.tape[-self.tape_length:]\n\n        elif order.otype == 'Ask':\n            self.asks.book_del(order)\n            if self.asks.n_orders > 0:\n                best_price = self.asks.lob_anon[0][0]\n                self.asks.best_price = best_price\n                self.asks.best_tid = self.asks.lob[best_price][1][0][2]\n            else:  # this side of book is empty\n                self.asks.best_price = None\n                self.asks.best_tid = None\n            \n            cancel_record = {'type': 'Cancel', 'time': time, 'order': order}\n            if tape_file is not None:\n                tape_file.write('CAN, %f, %d, Ask, %d\\n' % (time, order.qid, order.price))\n            self.tape.append(cancel_record)\n            # right-truncate the tape so that it keeps only the most recent items\n            self.tape = self.tape[-self.tape_length:]\n        else:\n            # neither bid nor ask?\n            sys.exit('bad order type in del_quote()')\n\n    def process_order(self, time, order, tape_file, vrbs):\n        \"\"\"\n        Process an order from a trader -- this is the BSE Matching Engine.\n        :param time: the current time.\n        :param order: the order to be processed.\n        :param tape_file: if is not None then write details of transaction to tape_file\n        :param vrbs: verbosity: if True, print a running commentary; if False, stay silent.\n        :return: transaction_record if the order results in a transaction, otherwise None.\n        \"\"\"\n        # receive an order and either add it to the relevant LOB (ie treat as limit order)\n        # or if it crosses the best counterparty offer, execute it (treat as a market order)\n        oprice = order.price\n        counterparty = None\n        price = None\n        [qid, response] = self.add_order(order, vrbs)  # add it to the order lists -- overwriting any previous order\n        order.qid = qid\n        if vrbs:\n            print('QUID: order.quid=%d' % order.qid)\n            print('RESPONSE: %s' % response)\n        best_ask = self.asks.best_price\n        best_ask_tid = self.asks.best_tid\n        best_bid = self.bids.best_price\n        best_bid_tid = self.bids.best_tid\n        if order.otype == 'Bid':\n            if self.asks.n_orders > 0 and best_bid >= best_ask:\n                # bid lifts the best ask\n                if vrbs:\n                    print(\"Bid $%s lifts best ask\" % oprice)\n                counterparty = best_ask_tid\n                price = best_ask  # bid crossed ask, so use ask price\n                if vrbs:\n                    print('counterparty, price', counterparty, price)\n                # delete the ask just crossed\n                self.asks.delete_best()\n                # delete the bid that was the latest order\n                self.bids.delete_best()\n        elif order.otype == 'Ask':\n            if self.bids.n_orders > 0 and best_ask <= best_bid:\n                # ask hits the best bid\n                if vrbs:\n                    print(\"Ask $%s hits best bid\" % oprice)\n                # remove the best bid\n                counterparty = best_bid_tid\n                price = best_bid  # ask crossed bid, so use bid price\n                if vrbs:\n                    print('counterparty, price', counterparty, price)\n                # delete the bid just crossed, from the exchange's records\n                self.bids.delete_best()\n                # delete the ask that was the latest order, from the exchange's records\n                self.asks.delete_best()\n        else:\n            # we should never get here\n            sys.exit('process_order() given neither Bid nor Ask')\n        # NB at this point we have deleted the order from the exchange's records\n        # but the two traders concerned still have to be notified\n        if vrbs:\n            print('counterparty %s' % counterparty)\n        if counterparty is not None:\n            # process the trade\n            if vrbs:\n                print('>>>>>>>>>>>>>>>>>TRADE t=%010.3f $%d %s %s' % (time, price, counterparty, order.tid))\n            transaction_record = {'type': 'Trade',\n                                  'time': time,\n                                  'price': price,\n                                  'party1': counterparty,\n                                  'party2': order.tid,\n                                  'qty': order.qty\n                                  }\n            if tape_file is not None:\n                tape_file.write('TRD, %f, %d\\n' % (time, price))\n            self.tape.append(transaction_record)\n            # right-truncate the tape so that it keeps only the most recent items\n            self.tape = self.tape[-self.tape_length:]\n\n            return transaction_record\n        else:\n            return None\n\n    def tape_dump(self, fname, fmode, tmode):\n        \"\"\"\n        Currently tape_dump only writes a list of transactions (i.e., it ignores any cancellations)\n        :param fname: filename to write to.\n        :param fmode: file-open write/append mode.\n        :param tmode: if set to 'wipe', wipes the tape clean after writing it to file.\n        :return:\n        \"\"\"\n        dumpfile = open(fname, fmode)\n        dumpfile.write('Event Type, Time, Price\\n')\n        for tapeitem in self.tape:\n            if tapeitem['type'] == 'Trade':\n                dumpfile.write('Trd, %010.3f, %s\\n' % (tapeitem['time'], tapeitem['price']))\n        dumpfile.close()\n        if tmode == 'wipe':\n            self.tape = []\n\n    def publish_lob(self, time, lob_file, vrbs):\n        \"\"\"\n        Returns the public LOB data published by the exchange, \n        i.e. the version of the LOB that's accessible to the traders.\n        :param time: the current time.\n        :param lob_file: \n        :param vrbs: verbosity: if True, print a running commentary; if False, stay silent.\n        :return: the public LOB data.\n        \"\"\"\n        public_data = dict()\n        public_data['time'] = time\n        public_data['bids'] = {'best': self.bids.best_price,\n                               'worst': self.bids.worstprice,\n                               'n': self.bids.n_orders,\n                               'lob': self.bids.lob_anon}\n        public_data['asks'] = {'best': self.asks.best_price,\n                               'worst': self.asks.worstprice,\n                               'sess_hi': self.asks.session_extreme,\n                               'n': self.asks.n_orders,\n                               'lob': self.asks.lob_anon}\n        public_data['QID'] = self.quote_id\n        public_data['tape'] = self.tape\n\n        if lob_file is not None:\n            # build a linear character-string summary of only those prices on LOB with nonzero quantities\n            lobstring = 'Bid:,'\n            n_bids = len(self.bids.lob_anon)\n            if n_bids > 0:\n                lobstring += '%d,' % n_bids\n                for lobitem in self.bids.lob_anon:\n                    price_str = '%d,' % lobitem[0]\n                    qty_str = '%d,' % lobitem[1]\n                    lobstring = lobstring + price_str + qty_str\n            else:\n                lobstring += '0,'\n            lobstring += 'Ask:,'\n            n_asks = len(self.asks.lob_anon)\n            if n_asks > 0:\n                lobstring += '%d,' % n_asks\n                for lobitem in self.asks.lob_anon:\n                    price_str = '%d,' % lobitem[0]\n                    qty_str = '%d,' % lobitem[1]\n                    lobstring = lobstring + price_str + qty_str\n            else:\n                lobstring += '0,'\n            # is this different to the last lob_string?\n            if lobstring != self.lob_string:\n                # write it\n                lob_file.write('%.3f, %s\\n' % (time, lobstring))\n                # remember it\n                self.lob_string = lobstring\n\n        if vrbs:\n            vstr = 'publish_lob: t=%f' % time\n            vstr += ' BID_lob=%s' % public_data['bids']['lob']\n            # vstr += 'best=%s; worst=%s; n=%s ' % (self.bids.best_price, self.bids.worstprice, self.bids.n_orders)\n            vstr += ' ASK_lob=%s' % public_data['asks']['lob']\n            # vstr += 'qid=%d' % self.quote_id\n            print(vstr)\n\n        return public_data\n\n\n# #################--Traders below here--#############\n\n\n# Trader superclass\n# all Traders have a trader id, bank balance, blotter, and list of orders to execute\nclass Trader:\n    \"\"\"The parent class for all types of robot trader in BSE\"\"\"\n\n    def __init__(self, ttype, tid, balance, params, time):\n        \"\"\"\n        Initializes a generic trader with attributes common to all/most types of trader\n        Some trader types (e.g. ZIP) then have additional specialised initialization steps\n        :param ttype: the trader type\n        :param tid: the trader I.D. (a non-negative integer)\n        :param balance: how much money it has in the bank when it is created\n        :param params: a set of parameter-values, for those trader-types that have parameters\n        :param time: the time this trader was created\n        \"\"\"\n        self.ttype = ttype          # what type / strategy this trader is\n        self.tid = tid              # trader unique ID code\n        self.balance = balance      # money in the bank\n        self.params = params        # parameters/extras associated with this trader-type or individual trader.\n        self.blotter = []           # record of trades executed\n        self.blotter_length = 100   # maximum length of blotter\n        self.orders = []            # customer orders currently being worked (fixed at len=1 in BSE1.x)\n        self.n_quotes = 0           # number of quotes live on LOB\n        self.birthtime = time       # used when calculating age of a trader/strategy\n        self.profitpertime = 0      # profit per unit time\n        self.profit_mintime = 60    # minimum duration in seconds for calculating profitpertime\n        self.n_trades = 0           # how many trades has this trader done?\n        self.lastquote = None       # record of what its last quote was\n\n    def __str__(self):\n        \"\"\" return a character-string that summarises a trader \"\"\"\n        return '[TID %s type %s balance %s blotter %s orders %s n_trades %s profitpertime %s]' \\\n               % (self.tid, self.ttype, self.balance, self.blotter, self.orders, self.n_trades, self.profitpertime)\n\n    def add_order(self, order, vrbs):\n        \"\"\"\n        What a trader calls when it receives a new customer order/assignment\n        :param order: the customer order/assignment to be added\n        :param vrbs: verbosity: if True, print a running commentary; if False, stay silent.\n        :return response: string to indicate whether the trader needs to cancel its current order on the LOB\n        \"\"\"\n        # in this version, trader has at most one order,\n        # if allow more than one, this needs to be self.orders.append(order)\n        if self.n_quotes > 0:\n            # this trader has a live quote on the LOB, from a previous customer order\n            # need response to signal cancellation/withdrawal of that quote\n            response = 'LOB_Cancel'\n        else:\n            response = 'Proceed'\n        self.orders = [order]\n        if vrbs:\n            print('add_order < response=%s' % response)\n        return response\n\n    def del_order(self, order):\n        \"\"\"What a trader calls when it wants to delete an existing customer order/assignment \"\"\"\n        if order is None:\n            pass    # this line is purely to stop PyCharm from warning about order being an unused parameter\n        # this is lazy: assumes each trader has only one customer order with quantity=1, so deleting sole order\n        self.orders = []\n\n    def profitpertime_update(self, time, birthtime, totalprofit):\n        \"\"\"\n        Calculates the trader's profit per unit time, but only if it has been alive longer than profit_mintime\n        This is to avoid situations where a trader is created and then immediately makes a profit and\n        hence the profit per unit time is a sky-high value, because the time_alive divisor is close to zero.\n        :param time: the current time.\n        :param birthtime: the time when the trader was created.\n        :param totalprofit: the trader's current total accumulated profit.\n        :return: profit per second.\n        \"\"\"\n        time_alive = (time - birthtime)\n        if time_alive >= self.profit_mintime:\n            profitpertime = totalprofit / time_alive\n        else:\n            # if it's not been alive long enough, divide it by mintime instead of actual time\n            profitpertime = totalprofit / self.profit_mintime\n        return profitpertime\n\n    def bookkeep(self, time, trade, order, vrbs):\n        \"\"\"\n        Update trader's individual records of transactions, profit/loss etc.\n        :param trade: details of the transaction that took place.\n        :param order: details of the customer order that led to the transaction.\n        :param vrbs: verbosity: if True, print a running commentary; if False, stay silent.\n        :param time: the current time.\n        :return: <nothing>\n        \"\"\"\n        outstr = \"\"\n        for order in self.orders:\n            outstr = outstr + str(order)\n\n        self.blotter.append(trade)  # add trade record to trader's blotter\n        self.blotter = self.blotter[-self.blotter_length:]  # right-truncate to keep to length\n\n        # NB What follows is **LAZY** -- assumes all orders are quantity=1\n        transactionprice = trade['price']\n        if self.orders[0].otype == 'Bid':\n            profit = self.orders[0].price - transactionprice\n        else:\n            profit = transactionprice - self.orders[0].price\n        self.balance += profit\n        self.n_trades += 1\n        self.profitpertime = self.balance / (time - self.birthtime)\n\n        if profit < 0:\n            print(profit)\n            print(trade)\n            print(order)\n            sys.exit('FAIL: negative profit')\n\n        if vrbs:\n            print('%s profit=%d balance=%d profit/time=%s' % (outstr, profit, self.balance, str(self.profitpertime)))\n        self.del_order(order)  # delete the order\n\n        # if the trader has multiple strategies (e.g. PRSH/PRDE/ZIPSH/ZIPDE) then there is more work to do...\n        if hasattr(self, 'strats') and hasattr(self, 'active_strat'):\n            if self.strats is not None:\n                self.strats[self.active_strat]['profit'] += profit\n                totalprofit = self.strats[self.active_strat]['profit']\n                birthtime = self.strats[self.active_strat]['start_t']\n                self.strats[self.active_strat]['pps'] = self.profitpertime_update(time, birthtime, totalprofit)\n\n    def respond(self, time, lob, trade, vrbs):\n        \"\"\"\n        Specify how a trader responds to events in the market.\n        For Trader superclass, this is minimal action, but expect it to be overloaded by specific trading strategies.\n        :param time:\n        :param lob:\n        :param trade:\n        :param vrbs: verbosity: if True, print a running commentary; if False, stay silent.\n        :return:\n        \"\"\"\n\n        # any trader subclass with custom respond() must include this update of profitpertime\n        self.profitpertime = self.profitpertime_update(time, self.birthtime, self.balance)\n        return None\n\n\nclass TraderGiveaway(Trader):\n    \"\"\"\n    Trader subclass Giveaway (GVWY): even dumber than a ZI-U: just give the deal away (but never make a loss)\n    \"\"\"\n\n    def getorder(self, time, countdown, lob):\n        \"\"\"\n        Create this trader's order to be sent to the exchange.\n        :param time: the current time.\n        :param countdown: how much time before market closes (not used by GVWY).\n        :param lob: the current state of the LOB.\n        :return: a new order from this trader.\n        \"\"\"\n        # this test for negative countdown is purely to stop PyCharm warning about unused parameter value\n        if countdown < 0:\n            sys.exit('Negative countdown')\n\n        if len(self.orders) < 1:\n            order = None\n        else:\n            quoteprice = self.orders[0].price\n            order = Order(self.tid,\n                          self.orders[0].otype,\n                          quoteprice,\n                          self.orders[0].qty,\n                          time, lob['QID'])\n            self.lastquote = order\n        return order\n\n\nclass TraderZIC(Trader):\n    \"\"\"\n    Trader subclass ZI-C: after Gode & Sunder 1993\n    \"\"\"\n\n    def getorder(self, time, countdown, lob):\n        \"\"\"\n        Create this trader's order to be sent to the exchange.\n        :param time: the current time.\n        :param countdown: how much time before market closes (not used by ZIC).\n        :param lob: the current state of the LOB.\n        :return: a new order from this trader.\n        \"\"\"\n        # this test for negative countdown is purely to stop PyCharm warning about unused parameter value\n        if countdown < 0:\n            sys.exit('Negative countdown')\n\n        if len(self.orders) < 1:\n            # no orders: return NULL\n            order = None\n        else:\n            minprice = lob['bids']['worst']\n            maxprice = lob['asks']['worst']\n            qid = lob['QID']\n            limit = self.orders[0].price\n            otype = self.orders[0].otype\n            if otype == 'Bid':\n                quoteprice = random.randint(int(minprice), int(limit))\n            else:\n                quoteprice = random.randint(int(limit), int(maxprice))\n                # NB should check it == 'Ask' and barf if not\n            order = Order(self.tid, otype, quoteprice, self.orders[0].qty, time, qid)\n            self.lastquote = order\n        return order\n\n\nclass TraderShaver(Trader):\n    \"\"\"\n    Trader subclass Shaver: shaves a penny off the best price;\n    but if there is no best price, creates \"stub quote\" at system max/min\n    \"\"\"\n\n    def getorder(self, time, countdown, lob):\n        \"\"\"\n        Create this trader's order to be sent to the exchange.\n        :param time: the current time.\n        :param countdown: how much time before market close (not used by SHVR).\n        :param lob: the current state of the LOB.\n        :return: a new order from this trader.\n        \"\"\"\n        # this test for negative countdown is purely to stop PyCharm warning about unused parameter value\n        if countdown < 0:\n            sys.exit('Negative countdown')\n\n        if len(self.orders) < 1:\n            order = None\n        else:\n            limitprice = self.orders[0].price\n            otype = self.orders[0].otype\n            if otype == 'Bid':\n                if lob['bids']['n'] > 0:\n                    quoteprice = lob['bids']['best'] + 1\n                    if quoteprice > limitprice:\n                        quoteprice = limitprice\n                else:\n                    quoteprice = lob['bids']['worst']\n            else:\n                if lob['asks']['n'] > 0:\n                    quoteprice = lob['asks']['best'] - 1\n                    if quoteprice < limitprice:\n                        quoteprice = limitprice\n                else:\n                    quoteprice = lob['asks']['worst']\n            order = Order(self.tid, otype, quoteprice, self.orders[0].qty, time, lob['QID'])\n            self.lastquote = order\n        return order\n\n\nclass TraderSniper(Trader):\n    \"\"\"\n    Trader subclass Sniper (SNPR), inspired by Kaplan's Sniper, BSE version is based on Shaver,\n    \"lurks\" until time remaining < threshold% of the trading session\n    then gets increasing aggressive, increasing \"shave thickness\" as time runs out\n    \"\"\"\n\n    def getorder(self, time, countdown, lob):\n        \"\"\"\n        Create this trader's order to be sent to the exchange.\n        :param time: the current time.\n        :param countdown: how much time before market closes.\n        :param lob: the current state of the LOB.\n        :return: a new order from this trader.\n        \"\"\"\n        lurk_threshold = 0.2\n        shavegrowthrate = 3\n        shave = int(1.0 / (0.01 + countdown / (shavegrowthrate * lurk_threshold)))\n        if (len(self.orders) < 1) or (countdown > lurk_threshold):\n            order = None\n        else:\n            limitprice = self.orders[0].price\n            otype = self.orders[0].otype\n\n            if otype == 'Bid':\n                if lob['bids']['n'] > 0:\n                    quoteprice = lob['bids']['best'] + shave\n                    if quoteprice > limitprice:\n                        quoteprice = limitprice\n                else:\n                    quoteprice = lob['bids']['worst']\n            else:\n                if lob['asks']['n'] > 0:\n                    quoteprice = lob['asks']['best'] - shave\n                    if quoteprice < limitprice:\n                        quoteprice = limitprice\n                else:\n                    quoteprice = lob['asks']['worst']\n            order = Order(self.tid, otype, quoteprice, self.orders[0].qty, time, lob['QID'])\n            self.lastquote = order\n        return order\n\n\nclass TraderPRZI(Trader):\n    \"\"\"\n    Cliff's Parameterized-Response Zero-Intelligence (PRZI) trader -- pronounced \"prezzie\"\n    but with added adaptive strategies, currently either...\n       ++  a k-point Stochastic Hill-Climber (SHC) hence PRZI-SHC,\n           PRZI-SHC pronounced \"prezzy-shuck\". Ticker symbol PRSH pronounced \"purrsh\";\n    or\n       ++ a simple differential evolution (DE) optimizer with pop_size=k, hence PRZE-DE or PRDE ('purdy\")\n\n    when optimizer == None then it implements plain-vanilla non-adaptive PRZI, with a fixed strategy-value.\n    \"\"\"\n\n    @staticmethod\n    def strat_csv_str(strat):\n        \"\"\"\n        Return trader's strategy as a csv-format string\n        (trivial in PRZI, but other traders with more complex strategies need this).\n        :param strat: the strategy specification (for PRZI, a real number in [-1.0,+1.0]\n        :return: the strategy as a scv-format string\n        \"\"\"\n        csv_str = 's=,%+5.3f, ' % strat\n        return csv_str\n\n    def mutate_strat(self, s, mode):\n        \"\"\"\n        How to mutate the PRZI strategy values when evolving / hill-climbing\n        :param s: the strategy to be mutated\n        :param mode:    'gauss'=> mutation is a draw from a zero-mean Gaussian;\n                        'uniform_whole_range\" => mutation is a draw from uniform distbn over [-1.0,+1.0].\n                        'uniform_bounded_range\" => mutation is a draw from a bounded unifrom distbn.\n        :return: the mutated strategy value\n        \"\"\"\n        s_min = self.strat_range_min\n        s_max = self.strat_range_max\n        if mode == 'gauss':\n            sdev = 0.05\n            newstrat = s\n            while newstrat == s:\n                newstrat = s + random.gauss(0.0, sdev)\n                # truncate to keep within range\n                newstrat = max(-1.0, min(1.0, newstrat))\n        elif mode == 'uniform_whole_range':\n            # draw uniformly from whole range\n            newstrat = random.uniform(-1.0, +1.0)\n        elif mode == 'uniform_bounded_range':\n            # draw uniformly from bounded range\n            newstrat = random.uniform(s_min, s_max)\n        else:\n            sys.exit('FAIL: bad mode in mutate_strat')\n        return newstrat\n\n    def strat_str(self):\n        \"\"\"\n        Pretty-print a string summarising this trader's strategy/strategies\n        :return: the string\n        \"\"\"\n        string = '%s: %s active_strat=[%d]:\\n' % (self.tid, self.ttype, self.active_strat)\n        for s in range(0, self.k):\n            strat = self.strats[s]\n            stratstr = '[%d]: s=%+f, start=%f, $=%f, pps=%f\\n' % \\\n                       (s, strat['stratval'], strat['start_t'], strat['profit'], strat['pps'])\n            string = string + stratstr\n\n        return string\n\n    def __init__(self, ttype, tid, balance, params, time):\n        \"\"\"\n        Construct a PRZI trader\n        :param ttype: the ticker-symbol for the type of trader (its strategy)\n        :param tid: the trader id\n        :param balance: the trader's bank balance\n        :param params: if params == \"landscape-mapper\" then it generates data for mapping the fitness landscape\n        :param time: the current time.\n        \"\"\"\n\n        vrbs = True\n\n        Trader.__init__(self, ttype, tid, balance, params, time)\n\n        # unpack the params\n        # for all three of PRZI, PRSH, and PRDE params can include strat_min and strat_max\n        # for PRSH and PRDE params should include values for optimizer and k\n        # if no params specified then defaults to PRZI with strat values in [-1.0,+1.0]\n\n        # default parameter values\n        k = 1\n        optimizer = None    # no optimizer => plain non-adaptive PRZI\n        s_min = -1.0\n        s_max = +1.0\n\n        # did call provide different params?\n        if type(params) is dict:\n            if 'k' in params:\n                k = params['k']\n            if 'optimizer' in params:\n                optimizer = params['optimizer']\n            s_min = params['strat_min']\n            s_max = params['strat_max']\n\n        self.optmzr = optimizer     # this determines whether it's PRZI, PRSH, or PRDE\n        self.k = k                  # number of sampling points (cf number of arms on a multi-armed-bandit, or pop-size)\n        self.theta0 = 100           # threshold-function limit value\n        self.m = 4                  # tangent-function multiplier\n        self.strat_wait_time = 7200     # how many secs do we give any one strat before switching?\n        self.strat_range_min = s_min    # lower-bound on randomly-assigned strategy-value\n        self.strat_range_max = s_max    # upper-bound on randomly-assigned strategy-value\n        self.active_strat = 0       # which of the k strategies are we currently playing? -- start with 0\n        self.prev_qid = None        # previous order i.d.\n        self.strat_eval_time = self.k * self.strat_wait_time   # time to cycle through evaluating all k strategies\n        self.last_strat_change_time = time  # what time did we last change strategies?\n        self.profit_epsilon = 0.0 * random.random()    # min profit-per-sec difference between strategies that counts\n        self.strats = []            # strategies awaiting initialization\n        self.pmax = None            # this trader's estimate of the maximum price the market will bear\n        self.pmax_c_i = math.sqrt(random.randint(1, 10))  # multiplier coefficient when estimating p_max\n        self.mapper_outfile = None\n        # differential evolution parameters all in one dictionary\n        self.diffevol = {'de_state': 'active_s0',          # initial state: strategy 0 is active (being evaluated)\n                         's0_index': self.active_strat,    # s0 starts out as active strat\n                         'snew_index': self.k,             # (k+1)th item of strategy list is DE's new strategy\n                         'snew_stratval': None,            # assigned later\n                         'F': 0.8                          # differential weight -- usually between 0 and 2\n                         }\n\n        start_t = time\n        profit = 0.0\n        profit_per_second = 0\n        lut_bid = None\n        lut_ask = None\n\n        for s in range(self.k + 1):\n            # initialise each of the strategies in sequence:\n            # for PRZI: only one strategy is needed\n            # for PRSH, one random initial strategy, then k-1 mutants of that initial strategy\n            # for PRDE, use draws from uniform distbn over whole range and a (k+1)th strategy is needed to hold s_new\n            strategy = None\n            if s == 0:\n                strategy = random.uniform(self.strat_range_min, self.strat_range_max)\n            else:\n                if self.optmzr == 'PRSH':\n                    # simple stochastic hill climber: cluster other strats around strat_0\n                    strategy = self.mutate_strat(self.strats[0]['stratval'], 'gauss')     # mutant of strats[0]\n                elif self.optmzr == 'PRDE':\n                    # differential evolution: seed initial strategies across whole space\n                    strategy = self.mutate_strat(self.strats[0]['stratval'], 'uniform_bounded_range')\n                else:\n                    # plain PRZI -- do nothing\n                    pass\n            # add to the list of strategies\n            if s == self.active_strat:\n                active_flag = True\n            else:\n                active_flag = False\n            self.strats.append({'stratval': strategy, 'start_t': start_t, 'active': active_flag,\n                                'profit': profit, 'pps': profit_per_second, 'lut_bid': lut_bid, 'lut_ask': lut_ask})\n            if self.optmzr is None:\n                # PRZI -- so we stop after one iteration\n                break\n            elif self.optmzr == 'PRSH' and s == self.k - 1:\n                # PRSH -- doesn't need the (k+1)th strategy\n                break\n\n        if self.params == 'landscape-mapper':\n            # replace seed+mutants set of strats with regularly-spaced strategy values over the whole range\n            self.strats = []\n            strategy_delta = 0.01\n            strategy = -1.0\n            k = 0\n            self.strats = []\n\n            while strategy <= +1.0:\n                self.strats.append({'stratval': strategy, 'start_t': start_t, 'active': False,\n                                    'profit': profit, 'pps': profit_per_second, 'lut_bid': lut_bid, 'lut_ask': lut_ask})\n                k += 1\n                strategy += strategy_delta\n            self.mapper_outfile = open('landscape_map.csv', 'w')\n            self.k = k\n            self.strat_eval_time = self.k * self.strat_wait_time\n\n        if vrbs:\n            print(\"%s\\n\" % self.strat_str())\n\n    def getorder(self, time, countdown, lob):\n        \"\"\"\n        Create this trader's order to be sent to the exchange.\n        :param time: the current time.\n        :param countdown: how much time before market close (not used by GVWY).\n        :param lob: the current state of the LOB.\n        :return: a new order from this trader.\n        \"\"\"\n        # this test for negative countdown is purely to stop PyCharm warning about unused parameter value\n        if countdown < 0:\n            sys.exit('Negative countdown')\n\n        def shvr_price(order_type, lim, pub_lob):\n            \"\"\"\n            Return value is what price a SHVR would quote in these circumstances\n            :param order_type: is the order bid or ask?\n            :param lim: limit price on the order.\n            :param pub_lob: the current state of the published LOB.\n            :return: The price a SHVR would quote given this LOB and limit-price.\n            \"\"\"\n\n            if order_type == 'Bid':\n                if pub_lob['bids']['n'] > 0:\n                    shvr_p = pub_lob['bids']['best'] + ticksize   # BSE ticksize is global var\n                    if shvr_p > lim:\n                        shvr_p = lim\n                else:\n                    shvr_p = pub_lob['bids']['worst']\n            else:\n                if pub_lob['asks']['n'] > 0:\n                    shvr_p = pub_lob['asks']['best'] - ticksize   # BSE ticksize is global var\n                    if shvr_p < lim:\n                        shvr_p = lim\n                else:\n                    shvr_p = pub_lob['asks']['worst']\n\n            # print('shvr_p=%f; ' % shvr_p)\n            return shvr_p\n\n        def calc_cdf_lut(strategy, t0, m, dirn, pmin, pmax):\n            \"\"\"\n            calculate cumulative distribution function (CDF) look-up table (LUT)\n            :param strategy: strategy-value in [-1,+1]\n            :param t0: constant used in the threshold function\n            :param m: constant used in the threshold function\n            :param dirn: direction: 'buy' or 'sell'\n            :param pmin: lower bound on discrete-valued price-range\n            :param pmax: upper bound on discrete-valued price-range\n            :return: {'strat': strategy, 'dirn': dirn, 'pmin': pmin, 'pmax': pmax, 'cdf_lut': cdf}\n            \"\"\"\n\n            # the threshold function used to clip\n            def threshold(theta0, x):\n                t = max(-1*theta0, min(theta0, x))\n                return t\n\n            epsilon = 0.000001  # used to catch DIV0 errors\n            lut_vrbs = False\n\n            if (strategy > 1.0) or (strategy < -1.0):\n                # out of range\n                sys.exit('PRSH FAIL: strategy=%f out of range\\n' % strategy)\n\n            if (dirn != 'buy') and (dirn != 'sell'):\n                # out of range\n                sys.exit('PRSH FAIL: bad dirn=%s\\n' % dirn)\n\n            if pmax < pmin:\n                # screwed\n                sys.exit('PRSH FAIL: pmax %f < pmin %f \\n' % (pmax, pmin))\n\n            if lut_vrbs:\n                print('PRSH calc_cdf_lut: strategy=%f dirn=%d pmin=%d pmax=%d\\n' % (strategy, dirn, pmin, pmax))\n\n            p_range = float(pmax - pmin)\n            if p_range < 1:\n                # special case: the SHVR-style strategy has shaved all the way to the limit price\n                # the lower and upper bounds on the interval are adjacent prices;\n                # so cdf is simply the limit-price with probability 1\n\n                if dirn == 'buy':\n                    cdf = [{'price': pmax, 'cum_prob': 1.0}]\n                else:   # must be a sell\n                    cdf = [{'price': pmin, 'cum_prob': 1.0}]\n\n                if lut_vrbs:\n                    print('\\n\\ncdf:', cdf)\n\n                return {'strat': strategy, 'dirn': dirn, 'pmin': pmin, 'pmax': pmax, 'cdf_lut': cdf}\n\n            c = threshold(t0, m * math.tan(math.pi * (strategy + 0.5)))\n\n            # catch div0 errors here\n            if abs(c) < epsilon:\n                if c > 0:\n                    c = epsilon\n                else:\n                    c = -epsilon\n\n            e2cm1 = math.exp(c) - 1\n\n            # calculate the discrete calligraphic-P function over interval [pmin, pmax]\n            # (i.e., this is Equation 8 in the PRZI Technical Note)\n            calp_interval = []\n            calp_sum = 0\n            for p in range(pmin, pmax + 1):\n                # normalize the price to proportion of its range\n                p_r = (p - pmin) / p_range  # p_r in [0.0, 1.0]\n                if strategy == 0.0:\n                    # special case: this is just ZIC\n                    cal_p = 1 / (p_range + 1)\n                elif strategy > 0:\n                    if dirn == 'buy':\n                        cal_p = (math.exp(c * p_r) - 1.0) / e2cm1\n                    else:   # dirn == 'sell'\n                        cal_p = (math.exp(c * (1 - p_r)) - 1.0) / e2cm1\n                else:   # self.strat < 0\n                    if dirn == 'buy':\n                        cal_p = 1.0 - ((math.exp(c * p_r) - 1.0) / e2cm1)\n                    else:   # dirn == 'sell'\n                        cal_p = 1.0 - ((math.exp(c * (1 - p_r)) - 1.0) / e2cm1)\n\n                if cal_p < 0:\n                    cal_p = 0   # just in case\n\n                calp_interval.append({'price': p, \"cal_p\": cal_p})\n                calp_sum += cal_p\n\n            if calp_sum <= 0:\n                print('calp_interval:', calp_interval)\n                print('pmin=%f, pmax=%f, calp_sum=%f' % (pmin, pmax, calp_sum))\n\n            cdf = []\n            cum_prob = 0\n            # now go thru interval summing and normalizing to give the CDF\n            for p in range(pmin, pmax + 1):\n                cal_p = calp_interval[p-pmin]['cal_p']\n                prob = cal_p / calp_sum\n                cum_prob += prob\n                cdf.append({'price': p, 'cum_prob': cum_prob})\n\n            if lut_vrbs:\n                print('\\n\\ncdf:', cdf)\n\n            return {'strat': strategy, 'dirn': dirn, 'pmin': pmin, 'pmax': pmax, 'cdf_lut': cdf}\n\n        vrbs = False\n\n        if vrbs:\n            print('t=%.1f PRSH getorder: %s, %s' % (time, self.tid, self.strat_str()))\n\n        if len(self.orders) < 1:\n            # no orders: return NULL\n            order = None\n        else:\n            # unpack the assignment-order\n            limit = self.orders[0].price\n            otype = self.orders[0].otype\n            qid = self.orders[0].qid\n\n            if self.prev_qid is None:\n                self.prev_qid = qid\n\n            if qid != self.prev_qid:\n                # customer-order i.d. has changed, so we're working a new customer-order now\n                # this is the time to switch arms\n                # print(\"New order! (how does it feel?)\")\n                pass\n\n            # get extreme limits on price interval\n            # lowest price the market will bear\n            minprice = int(lob['bids']['worst'])  # default assumption: worst bid price possible as defined by exchange\n\n            # trader's individual estimate highest price the market will bear\n            maxprice = self.pmax    # default assumption\n            if self.pmax is None:\n                maxprice = int(limit * self.pmax_c_i + 0.5)     # in the absence of any other info, guess\n                self.pmax = maxprice\n            elif lob['asks']['sess_hi'] is not None:\n                if self.pmax < lob['asks']['sess_hi']:        # some other trader has quoted higher than I expected\n                    maxprice = lob['asks']['sess_hi']         # so use that as my new estimate of highest\n                    self.pmax = maxprice\n\n            # use the cdf look-up table\n            # cdf_lut is a list of little dictionaries\n            # each dictionary has form: {'cum_prob':nnn, 'price':nnn}\n            # generate u=U(0,1) uniform disrtibution\n            # starting with the lowest nonzero cdf value at cdf_lut[0],\n            # walk up the lut (i.e., examine higher cumulative probabilities),\n            # until we're in the range of u; then return the relevant price\n\n            strat = self.strats[self.active_strat]['stratval']\n\n            # what price would a SHVR quote?\n            p_shvr = shvr_price(otype, limit, lob)\n\n            if otype == 'Bid':\n\n                p_max = int(limit)\n                if strat > 0.0:\n                    p_min = minprice\n                else:\n                    # shade the lower bound on the interval\n                    # away from minprice and toward shvr_price\n                    p_min = int(0.5 + (-strat * p_shvr) + ((1.0 + strat) * minprice))\n\n                lut_bid = self.strats[self.active_strat]['lut_bid']\n\n                if (lut_bid is None) or \\\n                        (lut_bid['strat'] != strat) or (lut_bid['pmin'] != p_min) or (lut_bid['pmax'] != p_max):\n                    # need to compute a new LUT\n                    if vrbs:\n                        print('New bid LUT')\n                    self.strats[self.active_strat]['lut_bid'] = \\\n                        calc_cdf_lut(strat, self.theta0, self.m, 'buy', p_min, p_max)\n\n                lut = self.strats[self.active_strat]['lut_bid']\n\n            else:   # otype == 'Ask'\n\n                p_min = int(limit)\n                if strat > 0.0:\n                    p_max = maxprice\n                else:\n                    # shade the upper bound on the interval\n                    # away from maxprice and toward shvr_price\n                    p_max = int(0.5 + (-strat * p_shvr) + ((1.0 + strat) * maxprice))\n                    if p_max < p_min:\n                        # this should never happen, but just in case it does...\n                        p_max = p_min\n\n                lut_ask = self.strats[self.active_strat]['lut_ask']\n\n                if (lut_ask is None) or \\\n                        (lut_ask['strat'] != strat) or \\\n                        (lut_ask['pmin'] != p_min) or \\\n                        (lut_ask['pmax'] != p_max):\n                    # need to compute a new LUT\n                    if vrbs:\n                        print('New ask LUT')\n                    self.strats[self.active_strat]['lut_ask'] = \\\n                        calc_cdf_lut(strat, self.theta0, self.m, 'sell', p_min, p_max)\n\n                lut = self.strats[self.active_strat]['lut_ask']\n\n            vrbs = False\n            if vrbs:\n                print('PRZI strat=%f LUT=%s \\n \\n' % (strat, lut))\n                # for debugging: print a table of lut: price and cum_prob, with the discrete derivative (gives PMF).\n                last_cprob = 0.0\n                for lut_entry in lut['cdf_lut']:\n                    cprob = lut_entry['cum_prob']\n                    print('%d, %f, %f' % (lut_entry['price'], cprob - last_cprob, cprob))\n                    last_cprob = cprob\n                print('\\n')\n                \n                # print ('[LUT print suppressed]')\n            \n            # do inverse lookup on the LUT to find the price\n            quoteprice = None\n            u = random.random()\n            for entry in lut['cdf_lut']:\n                if u < entry['cum_prob']:\n                    quoteprice = entry['price']\n                    break\n\n            order = Order(self.tid, otype, quoteprice, self.orders[0].qty, time, lob['QID'])\n\n            self.lastquote = order\n\n        return order\n\n    def bookkeep(self, time, trade, order, vrbs):\n        \"\"\"\n        Update trader's individual records of transactions, profit/loss etc.\n        :param trade: details of the transaction that took place\n        :param order: details of the customer order that led to the transaction\n        :param vrbs: if True then print a running commentary of what's going on\n        :param time: the current time\n        :return: (nothing)\n        \"\"\"\n\n        outstr = \"\"\n        for order in self.orders:\n            outstr = outstr + str(order)\n\n        self.blotter.append(trade)  # add trade record to trader's blotter\n        self.blotter = self.blotter[-self.blotter_length:]      # right-truncate to keep to length\n\n        # NB What follows is **LAZY** -- assumes all orders are quantity=1\n        transactionprice = trade['price']\n        if self.orders[0].otype == 'Bid':\n            profit = self.orders[0].price - transactionprice\n        else:\n            profit = transactionprice - self.orders[0].price\n        self.balance += profit\n        self.n_trades += 1\n        self.profitpertime = self.balance / (time - self.birthtime)\n\n        if profit < 0:\n            print(profit)\n            print(trade)\n            print(order)\n            sys.exit('PRSH FAIL: negative profit')\n\n        if vrbs:\n            print('%s profit=%d balance=%d profit/time=%d' % (outstr, profit, self.balance, self.profitpertime))\n        self.del_order(order)  # delete the order\n\n        self.strats[self.active_strat]['profit'] += profit\n        time_alive = time - self.strats[self.active_strat]['start_t']\n        if time_alive > 0:\n            profit_per_second = self.strats[self.active_strat]['profit'] / time_alive\n            self.strats[self.active_strat]['pps'] = profit_per_second\n        else:\n            # if it trades at the instant it is born then it would have infinite profit-per-second, which is insane\n            # to keep things sensible when time_alive == 0 we say the profit per second is whatever the actual profit is\n            self.strats[self.active_strat]['pps'] = profit\n\n    def respond(self, time, lob, trade, vrbs):\n        \"\"\"\n        Respond to the current state of the LOB.\n        For strategy-optimizers PRSH and PRDE, this can involve switching stratregy, and/or generating new strategies.\n        :param time: the current time.\n        :param lob: the current state of the LOB.\n        :param trade: details of most recent trade, if any.\n        :param vrbs: if True then print messages explaining what is going on.\n        :return:\n        \"\"\"\n        # \"PRSH\" is a very basic form of stochastic hill-climber (SHC) that's v easy to understand and to code\n        # it cycles through the k different strats until each has been operated for at least eval_time seconds\n        # but a strat that does nothing will get swapped out if it's been running for no_deal_time without a deal\n        # then the strats with the higher total accumulated profit is retained,\n        # and mutated versions of it are copied into the other k-1 strats\n        # then all counters are reset, and this is repeated indefinitely\n        #\n        # \"PRDE\" uses a basic form of Differential Evolution. This maintains a population of at least four strats\n        # iterates indefinitely on:\n        #       shuffle the set of strats;\n        #       name the first four strats s0 to s3;\n        #       create new_strat=s1+f*(s2-s3);\n        #       evaluate fitness of s0 and new_strat;\n        #       if (new_strat fitter than s0) then new_strat replaces s0.\n        #\n        # todo: add in other optimizer algorithms that are cleverer than these\n        #  e.g. inspired by multi-arm-bandit algos like like epsilon-greedy, softmax, or upper confidence bound (UCB)\n\n        def strat_activate(t, s_index):\n            \"\"\"\n            Activate a specified strategy\n            :param t: the current time\n            :param s_index: the index of the strategy in the list of strategies\n            :return: <nothing>\n            \"\"\"\n            # print('t=%f Strat_activate, index=%d, active=%s' % (t, s_index, self.strats[s_index]['active'] ))\n            self.strats[s_index]['start_t'] = t\n            self.strats[s_index]['active'] = True\n            self.strats[s_index]['profit'] = 0.0\n            self.strats[s_index]['pps'] = 0.0\n\n        vrbs = False\n\n        # first update each active strategy's profit-per-second (pps) value -- this is the \"fitness\" of each strategy\n        for s in self.strats:\n            # debugging check: make profit be directly proportional to strategy, no noise\n            # s['profit'] = 100 * abs(s['stratval'])\n            # update pps\n            active_flag = s['active']\n            if active_flag:\n                s['pps'] = self.profitpertime_update(time, s['start_t'], s['profit'])\n\n        if self.optmzr == 'PRSH':\n\n            if vrbs:\n                # print('t=%f %s PRSH respond: shc_algo=%s eval_t=%f max_wait_t=%f' %\n                #     (time, self.tid, shc_algo, self.strat_eval_time, self.strat_wait_time))\n                pass\n\n            # do we need to swap strategies?\n            # this is based on time elapsed since last reset -- waiting for the current strategy to get a deal\n            # -- otherwise a hopeless strategy can just sit there for ages doing nothing,\n            # which would disadvantage the *other* strategies because they would never get a chance to score any profit.\n\n            # NB this *cycles* through the available strats in sequence\n\n            s = self.active_strat\n            time_elapsed = time - self.last_strat_change_time\n            if time_elapsed > self.strat_wait_time:\n                # we have waited long enough: swap to another strategy\n                self.strats[s]['active'] = False\n\n                new_strat = s + 1\n                if new_strat > self.k - 1:\n                    new_strat = 0\n\n                self.active_strat = new_strat\n                self.strats[new_strat]['active'] = True\n                self.last_strat_change_time = time\n\n                if vrbs:\n                    swt = self.strat_wait_time\n                    print('t=%.3f (%.2fdays), %s PRSHrespond: strat[%d] elpsd=%.3f; wait_t=%.3f, pps=%f, new strat=%d' %\n                          (time, time/86400, self.tid, s, time_elapsed, swt, self.strats[s]['pps'], new_strat))\n\n            # code below here deals with creating a new set of k-1 mutants from the best of the k strats\n\n            # assume that all strats have had long enough, and search for evidence to the contrary\n            all_old_enough = True\n            for s in self.strats:\n                lifetime = time - s['start_t']\n                if lifetime < self.strat_eval_time:\n                    all_old_enough = False\n                    break\n\n            if all_old_enough:\n                # all strategies have had long enough: which has made most profit?\n\n                # sort them by profit\n                strats_sorted = sorted(self.strats, key=lambda k: k['pps'], reverse=True)\n                # strats_sorted = self.strats     # use this as a control: unsorts the strats, gives pure random walk.\n\n                if vrbs:\n                    print('PRSH %s: strat_eval_time=%f, all_old_enough=True' % (self.tid, self.strat_eval_time))\n                    for s in strats_sorted:\n                        print('s=%f, start_t=%f, lifetime=%f, $=%f, pps=%f' %\n                              (s['stratval'], s['start_t'], time-s['start_t'], s['profit'], s['pps']))\n\n                if self.params == 'landscape-mapper':\n                    for s in self.strats:\n                        self.mapper_outfile.write('time, %f, strat, %f, pps, %f\\n' %\n                                                  (time, s['stratval'], s['pps']))\n                    self.mapper_outfile.flush()\n                    sys.exit()\n\n                else:\n                    # if the difference between the top two strats is too close to call then flip a coin\n                    # this is to prevent the same good strat being held constant simply by chance cos it is at index [0]\n                    best_strat = 0\n                    prof_diff = strats_sorted[0]['pps'] - strats_sorted[1]['pps']\n                    if abs(prof_diff) < self.profit_epsilon:\n                        # they're too close to call, so just flip a coin\n                        best_strat = random.randint(0, 1)\n\n                    if best_strat == 1:\n                        # need to swap strats[0] and strats[1]\n                        tmp_strat = strats_sorted[0]\n                        strats_sorted[0] = strats_sorted[1]\n                        strats_sorted[1] = tmp_strat\n\n                    # the sorted list of strats replaces the existing list\n                    self.strats = strats_sorted\n\n                    # at this stage, strats_sorted[0] is our newly-chosen elite-strat, about to replicate\n\n                    # now replicate and mutate the elite into all the other strats\n                    for s in range(1, self.k):    # note range index starts at one not zero (elite is at [0])\n                        self.strats[s]['stratval'] = self.mutate_strat(self.strats[0]['stratval'], 'gauss')\n                        self.strats[s]['start_t'] = time\n                        self.strats[s]['profit'] = 0.0\n                        self.strats[s]['pps'] = 0.0\n                    # and then update (wipe) records for the elite\n                    self.strats[0]['start_t'] = time\n                    self.strats[0]['profit'] = 0.0\n                    self.strats[0]['pps'] = 0.0\n                    self.active_strat = 0\n\n                if vrbs:\n                    print('%s: strat_eval_time=%f, MUTATED:' % (self.tid, self.strat_eval_time))\n                    for s in self.strats:\n                        print('s=%f start_t=%f, lifetime=%f, $=%f, pps=%f' %\n                              (s['stratval'], s['start_t'], time-s['start_t'], s['profit'], s['pps']))\n\n        elif self.optmzr == 'PRDE':\n            # simple differential evolution\n\n            # only initiate diff-evol once the active strat has been evaluated for long enough\n            actv_lifetime = time - self.strats[self.active_strat]['start_t']\n            if actv_lifetime >= self.strat_wait_time:\n\n                if self.k < 4:\n                    sys.exit('FAIL: k too small for diffevol')\n\n                if self.diffevol['de_state'] == 'active_s0':\n                    self.strats[self.active_strat]['active'] = False\n                    # we've evaluated s0, so now we need to evaluate s_new\n                    self.active_strat = self.diffevol['snew_index']\n                    strat_activate(time, self.active_strat)\n\n                    self.diffevol['de_state'] = 'active_snew'\n\n                elif self.diffevol['de_state'] == 'active_snew':\n                    # now we've evaluated s_0 and s_new, so we can do DE adaptive step\n                    if vrbs:\n                        print('PRDE trader %s' % self.tid)\n                    i_0 = self.diffevol['s0_index']\n                    i_new = self.diffevol['snew_index']\n                    fit_0 = self.strats[i_0]['pps']\n                    fit_new = self.strats[i_new]['pps']\n\n                    if verbose:\n                        print('DiffEvol: t=%.1f, i_0=%d, i0fit=%f, i_new=%d, i_new_fit=%f' %\n                              (time, i_0, fit_0, i_new, fit_new))\n\n                    if fit_new >= fit_0:\n                        # new strat did better than old strat0, so overwrite new into strat0\n                        self.strats[i_0]['stratval'] = self.strats[i_new]['stratval']\n\n                    # do differential evolution\n\n                    # pick four individual strategies at random, but they must be distinct\n                    stratlist = list(range(0, self.k))    # create sequential list of strategy-numbers\n                    random.shuffle(stratlist)             # shuffle the list\n\n                    # s0 is next iteration's candidate for possible replacement\n                    self.diffevol['s0_index'] = stratlist[0]\n\n                    # s1, s2, s3 used in DE to create new strategy, potential replacement for s0\n                    s1_index = stratlist[1]\n                    s2_index = stratlist[2]\n                    s3_index = stratlist[3]\n\n                    # unpack the actual strategy values\n                    s1_stratval = self.strats[s1_index]['stratval']\n                    s2_stratval = self.strats[s2_index]['stratval']\n                    s3_stratval = self.strats[s3_index]['stratval']\n\n                    # this is the differential evolution \"adaptive step\": create a new individual\n                    new_stratval = s1_stratval + self.diffevol['F'] * (s2_stratval - s3_stratval)\n\n                    # clip to bounds\n                    new_stratval = max(-1, min(+1, new_stratval))\n\n                    # record it for future use (s0 will be evaluated first, then s_new)\n                    self.strats[self.diffevol['snew_index']]['stratval'] = new_stratval\n\n                    if verbose:\n                        print('DiffEvol: t=%.1f, s0=%d, s1=%d, (s=%+f), s2=%d, (s=%+f), s3=%d, (s=%+f), sNew=%+f' %\n                              (time, self.diffevol['s0_index'],\n                               s1_index, s1_stratval, s2_index, s2_stratval, s3_index, s3_stratval, new_stratval))\n\n                    # DC's intervention for fully converged populations\n                    # is the stddev of the strategies in the population equal/close to zero?\n                    strat_sum = 0.0\n                    for s in range(self.k):\n                        strat_sum += self.strats[s]['stratval']\n                    strat_mean = strat_sum / self.k\n                    sumsq = 0.0\n                    for s in range(self.k):\n                        diff = self.strats[s]['stratval'] - strat_mean\n                        sumsq += (diff * diff)\n                    strat_stdev = math.sqrt(sumsq / self.k)\n                    if vrbs:\n                        print('t=,%.1f, MeanStrat=, %+f, stdev=,%f' % (time, strat_mean, strat_stdev))\n                    if strat_stdev < 0.0001:\n                        # this population has converged\n                        # mutate one strategy at random\n                        randindex = random.randint(0, self.k - 1)\n                        self.strats[randindex]['stratval'] = random.uniform(-1.0, +1.0)\n                        if verbose:\n                            print('Converged pop: set strategy %d to %+f' %\n                                  (randindex, self.strats[randindex]['stratval']))\n\n                    # set up next iteration: first evaluate s0\n                    self.active_strat = self.diffevol['s0_index']\n                    strat_activate(time, self.active_strat)\n\n                    self.diffevol['de_state'] = 'active_s0'\n\n                else:\n                    sys.exit('FAIL: self.diffevol[\\'de_state\\'] not recognized')\n\n        elif self.optmzr is None:\n            # this is PRZI -- nonadaptive, no optimizer, nothing to change here.\n            pass\n\n        else:\n            sys.exit('FAIL: bad value for self.optmzr')\n\n\nclass TraderZIP(Trader):\n    \"\"\"\n    The Zero-Intelligence-Plus (ZIP) adaptive trading strategy of Cliff (1997).\n    The code here implements the original ZIP, and also the strategy-optimizing variuants ZIPSH and ZIPDE.\n    \"\"\"\n\n    # ZIP init key param-values are those used in Cliff's 1997 original HP Labs tech report\n    # NB this implementation keeps separate margin values for buying & selling,\n    #    so a single trader can both buy AND sell\n    #    -- in the original, traders were either buyers OR sellers\n\n    @staticmethod\n    def strat_csv_str(strat):\n        \"\"\"\n        Take a ZIP strategy vector and return it as a csv-format string.\n        :param strat: the vector of values for the ZIP trader's strategy\n        :return: the csv-format string.\n        \"\"\"\n        if strat is None:\n            csv_str = 'None, '\n        else:\n            csv_str = 'mBuy=,%+5.3f, mSel=,%+5.3f, b=,%5.3f, m=,%5.3f, ca=,%6.4f, cr=,%6.4f, ' % \\\n                      (strat['m_buy'], strat['m_sell'], strat['beta'], strat['momntm'], strat['ca'], strat['cr'])\n        return csv_str\n\n    @staticmethod\n    def mutate_strat(s, mode):\n        \"\"\"\n        How to mutate the strategy values when evolving / hill-climbing\n        :param s: the strategy to be mutated.\n        :param mode: specify Gaussian or some other form of distribution for the mutation delta (currently only Gauss).\n        :return: the mutated strategy.\n        \"\"\"\n\n        def gauss_mutate_clip(value, sdev, range_min, range_max):\n            \"\"\"\n            Mutation of strategy-value by injection of zero-mean Gaussian noise, followed by clipping to keep in range.\n            :param value: the value to be mutated.\n            :param sdev: the standard deviation on the Gaussian noise.\n            :param range_min: lower bound on the range.\n            :param range_max: upper bound opn the range.\n            :return: the mutated value.\n            \"\"\"\n            mut_val = value\n            while mut_val == value:\n                mut_val = value + random.gauss(0.0, sdev)\n                if mut_val > range_max:\n                    mut_val = range_max\n                elif mut_val < range_min:\n                    mut_val = range_min\n            return mut_val\n\n        # mutate each element of a ZIP strategy independently\n        # and clip each to remain within bounds\n        if mode == 'gauss':\n            big_sdev = 0.025\n            small_sdev = 0.0025\n            margin_buy = gauss_mutate_clip(s['m_buy'], big_sdev, -1.0, 0)\n            margin_sell = gauss_mutate_clip(s['m_sell'], big_sdev, 0.0, 1.0)\n            beta = gauss_mutate_clip(s['beta'], big_sdev, 0.0, 1.0)\n            momntm = gauss_mutate_clip(s['momntm'], big_sdev, 0.0, 1.0)\n            ca = gauss_mutate_clip(s['ca'], small_sdev, 0.0, 1.0)\n            cr = gauss_mutate_clip(s['cr'], small_sdev, 0.0, 1.0)\n            new_strat = {'m_buy': margin_buy, 'm_sell': margin_sell, 'beta': beta, 'momntm': momntm, 'ca': ca, 'cr': cr}\n        else:\n            sys.exit('FAIL: bad mode in mutate_strat')\n        return new_strat\n\n    def __init__(self, ttype, tid, balance, params, time):\n        \"\"\"\n        Create a ZIP/ZIPSH/ZIPDE trader.\n        :param ttype: the string identifying the trader-type (what strategy is this).\n        :param tid: the trader i.d. string.\n        :param balance: the starting bank balance for this trader.\n        :param params: any additional parameters.\n        :param time: the current time.\n        \"\"\"\n\n        Trader.__init__(self, ttype, tid, balance, params, time)\n\n        # this set of one-liner functions named init_*() are just to make the init params obvious for ease of editing\n        # for ZIP, a strategy is specified as a 6-tuple: (margin_buy, margin_sell, beta, momntm, ca, cr)\n        # the 'default' values mentioned in comments below come from Cliff 1997 -- good ranges for most situations\n\n        def init_beta():\n            \"\"\"in Cliff 1997 the initial beta values are U(0.1, 0.5)\"\"\"\n            return random.uniform(0.1, 0.5)\n\n        def init_momntm():\n            \"\"\"in Cliff 1997 the initial momentum values are U(0.0, 0.1)\"\"\"\n            return random.uniform(0.0, 0.1)\n\n        def init_ca():\n            # in Cliff 1997 c_a was a system constant, the same for all traders, set to 0.05\n            # here we take the liberty of introducing some variation\n            return random.uniform(0.01, 0.05)\n\n        def init_cr():\n            # in Cliff 1997 c_r was a system constant, the same for all traders, set to 0.05\n            # here we take the liberty of introducing some variation\n            return random.uniform(0.01, 0.05)\n\n        def init_margin():\n            # in Cliff 1997 the initial margin values are U(0.05, 0.35)\n            return random.uniform(0.05, 0.35)\n\n        def init_stratwaittime():\n            # not in Cliff 1997: use whatever limits you think best.\n            return 7200 + random.randint(0, 3600)\n\n        # unpack the params\n        # for ZIPSH and ZIPDE params should include values for optimizer and k\n        # if no params specified then defaults to ZIP with strat values as in Cliff1997\n\n        # default parameter values\n        k = 1\n        optimizer = None    # no optimizer => plain non-optimizing ZIP\n        logging = False\n\n        # did call provide different params?\n        if type(params) is dict:\n            if 'k' in params:\n                k = params['k']\n            if 'optimizer' in params:\n                optimizer = params['optimizer']\n            self.logfile = None\n            if 'logfile' in params:\n                logging = True\n                logfilename = params['logfile'] + '_' + tid + '_log.csv'\n                self.logfile = open(logfilename, 'w')\n\n        # the following set of variables are needed for original ZIP *and* for its optimizing extensions e.g. ZIPSH\n        self.logging = logging\n        self.willing = 1\n        self.able = 1\n        self.job = None             # this gets switched to 'Bid' or 'Ask' depending on order-type\n        self.active = False         # gets switched to True while actively working an order\n        self.prev_change = 0        # this was called last_d in Cliff'97\n        self.beta = init_beta()\n        self.momntm = init_momntm()\n        self.ca = init_ca()         # self.ca & self.cr were hard-coded in '97 but parameterised later\n        self.cr = init_cr()\n        self.margin = None          # this was called profit in Cliff'97\n        self.margin_buy = -1.0 * init_margin()\n        self.margin_sell = init_margin()\n        self.price = None\n        self.limit = None\n        self.prev_best_bid_p = None     # best bid price on LOB on previous update\n        self.prev_best_bid_q = None     # best bid quantity on LOB on previous update\n        self.prev_best_ask_p = None     # best ask price on LOB on previous update\n        self.prev_best_ask_q = None     # best ask quantity on LOB on previous update\n\n        # the following set of variables are needed only by ZIP with added hyperparameter optimization (e.g. ZIPSH)\n        self.k = k                  # how many strategies evaluated at any one time?\n        self.optmzr = optimizer     # what form of strategy-optimizer we're using\n        self.strats = None          # the list of strategies, each of which is a dictionary\n        self.strat_wait_time = init_stratwaittime()     # how many secs do we give any one strat before switching?\n        self.strat_eval_time = self.k * self.strat_wait_time  # time to cycle through evaluating all k strategies\n        self.last_strat_change_time = time  # what time did we last change strategies?\n        self.active_strat = 0       # which of the k strategies are we currently playing? -- start with 0\n        self.profit_epsilon = 0.0 * random.random()     # min profit-per-sec difference between strategies that counts\n\n        if self.optmzr is not None and k > 1:\n            # we're doing some form of k-armed strategy-optimization with multiple strategies\n            self.strats = []\n            # strats[0] is whatever we've just assigned, and is the active strategy\n            strategy = {'m_buy': self.margin_buy, 'm_sell': self.margin_sell, 'beta': self.beta,\n                        'momntm': self.momntm, 'ca': self.ca, 'cr': self.cr}\n            self.strats.append({'stratvec': strategy, 'start_t': time, 'active': True,\n                                'profit': 0, 'pps': 0, 'evaluated': False})\n\n            # rest of *initial* strategy set is generated from same distributions, but these are all inactive\n            for s in range(1, k):\n                strategy = {'m_buy': -1.0 * init_margin(), 'm_sell': init_margin(), 'beta': init_beta(),\n                            'momntm': init_momntm(), 'ca': init_ca(), 'cr': init_cr()}\n                self.strats.append({'stratvec': strategy, 'start_t': time, 'active': False,\n                                    'profit': 0, 'pps': 0, 'evaluated': False})\n\n        if self.logging:\n            self.logfile.write('ZIP, Tid, %s, ttype, %s, optmzr, %s, strat_wait_time, %f, n_strats=%d:\\n' %\n                               (self.tid, self.ttype, self.optmzr, self.strat_wait_time, self.k))\n            for s in self.strats:\n                self.logfile.write(str(s)+'\\n')\n\n    def getorder(self, time, countdown, lob):\n        \"\"\"\n        Create the next order for this trader\n        :param time: the current time\n        :param countdown: time remaining until market closes (not used in ZIP)\n        :param lob: the current state of the LOB\n        :return: this trader's next order.\n        \"\"\"\n        # this test for negative countdown is purely to stop PyCharm warning about unused parameter value\n        if countdown < 0:\n            sys.exit('Negative countdown')\n\n        if len(self.orders) < 1:\n            self.active = False\n            order = None\n        else:\n            self.active = True\n            self.limit = self.orders[0].price\n            self.job = self.orders[0].otype\n            if self.job == 'Bid':\n                # currently a buyer (working a bid order)\n                self.margin = self.margin_buy\n            else:\n                # currently a seller (working a sell order)\n                self.margin = self.margin_sell\n            quoteprice = int(self.limit * (1 + self.margin))\n\n            lastprice = -1  # dummy value for if there is no lastprice\n            if self.lastquote is not None:\n                lastprice = self.lastquote.price\n\n            self.price = quoteprice\n            order = Order(self.tid, self.job, quoteprice, self.orders[0].qty, time, lob['QID'])\n            self.lastquote = order\n\n            if self.logging and order.price != lastprice:\n                self.logfile.write('%f, Order:, %s\\n' % (time, str(order)))\n        return order\n\n    def respond(self, time, lob, trade, vrbs):\n        \"\"\"\n        Update ZIP profit margin on basis of what happened in market.\n        For ZIPSH and ZIPDE, also maybe switch strategy and/or generate new strategies to evaluate.\n        :param time: the current time.\n        :param lob: the current state of the LOB.\n        :param trade: details of most recent trade, if any.\n        :param vrbs: if True then print a running commentary of what is going on.\n        :return: snapshot: if Ture, then the caller of respond() should print the next frame of system snapshot data.\n        \"\"\"\n        # ZIP trader responds to market events, altering its margin\n        # does this whether it currently has an order to work or not\n\n        def target_up(price):\n            \"\"\" Generate a higher target price by randomly perturbing given price\"\"\"\n            ptrb_abs = self.ca * random.random()  # absolute shift\n            ptrb_rel = price * (1.0 + (self.cr * random.random()))  # relative shift\n            target = int(round(ptrb_rel + ptrb_abs, 0))\n            # #                        print('TargetUp: %d %d\\n' % (price,target))\n            return target\n\n        def target_down(price):\n            \"\"\" Generate a lower target price by randomly perturbing given price\"\"\"\n            ptrb_abs = self.ca * random.random()  # absolute shift\n            ptrb_rel = price * (1.0 - (self.cr * random.random()))  # relative shift\n            target = int(round(ptrb_rel - ptrb_abs, 0))\n            # #                        print('TargetDn: %d %d\\n' % (price,target))\n            return target\n\n        def willing_to_trade(price):\n            \"\"\" Am I willing to trade at this price?\"\"\"\n            willing = False\n            if self.job == 'Bid' and self.active and self.price >= price:\n                willing = True\n            if self.job == 'Ask' and self.active and self.price <= price:\n                willing = True\n            return willing\n\n        def profit_alter(price):\n            \"\"\"\n            ZIP profit-margin update on basis of target price -- updates self.margin.\n            :param price: the target price.\n            :return: <nothing>\n            \"\"\"\n            oldprice = self.price\n            diff = price - oldprice\n            change = ((1.0 - self.momntm) * (self.beta * diff)) + (self.momntm * self.prev_change)\n            self.prev_change = change\n            newmargin = ((self.price + change) / self.limit) - 1.0\n\n            if self.job == 'Bid':\n                if newmargin < 0.0:\n                    self.margin_buy = newmargin\n                    self.margin = newmargin\n            else:\n                if newmargin > 0.0:\n                    self.margin_sell = newmargin\n                    self.margin = newmargin\n\n            # set the price from limit and profit-margin\n            self.price = int(round(self.limit * (1.0 + self.margin), 0))\n\n        def load_strat(stratvec, birthtime):\n            \"\"\"\n            Copy the strategy vector into the ZIP trader's params and timestamp it.\n            :param stratvec: the strategy vector.\n            :param birthtime: the timestamp.\n            :return: <nothing>\n            \"\"\"\n            self.margin_buy = stratvec['m_buy']\n            self.margin_sell = stratvec['m_sell']\n            self.beta = stratvec['beta']\n            self.momntm = stratvec['momntm']\n            self.ca = stratvec['ca']\n            self.cr = stratvec['cr']\n            # bookkeeping\n            self.n_trades = 0\n            self.birthtime = birthtime\n            self.balance = 0\n            self.profitpertime = 0\n\n        def strat_activate(t, s_index):\n            \"\"\"\n            Activate a specified strategy-vector.\n            :param t: the current time.\n            :param s_index: the index of the strategy to be activated.\n            :return: <nothing>\n            \"\"\"\n            # print('t=%f Strat_activate, index=%d, active=%s' % (t, s_index, self.strats[s_index]['active'] ))\n            self.strats[s_index]['start_t'] = t\n            self.strats[s_index]['active'] = True\n            self.strats[s_index]['profit'] = 0.0\n            self.strats[s_index]['pps'] = 0.0\n            self.strats[s_index]['evaluated'] = False\n\n        # snapshot says whether the caller of respond() should print next frame of system snapshot data\n        snapshot = False\n\n        if self.optmzr == 'ZIPSH':\n\n            # ZIP with simple-stochastic-hillclimber optimization of strategy (hyperparameter values)\n\n            # NB this *cycles* through the available strats in sequence (i.e., it doesn't shuffle them)\n\n            # first update the pps for each active strategy\n            for s in self.strats:\n                # update pps\n                active_flag = s['active']\n                if active_flag:\n                    s['pps'] = self.profitpertime_update(time, s['start_t'], s['profit'])\n\n            # have we evaluated all the strategies?\n            # (could instead just compare active_strat to k, but checking them all in sequence is arguably clearer)\n            # assume that all strats have been evaluated, and search for evidence to the contrary\n            all_evaluated = True\n            for s in self.strats:\n                if s['evaluated'] is False:\n                    all_evaluated = False\n                    break\n\n            if all_evaluated:\n                # time to generate a new set/population of k candidate strategies\n                # NB when the final strategy in the trader's set/popln is evaluated, the set is then sorted into\n                # descending order of profitability, so when we get to here we know that strats[0] is elite\n\n                if vrbs and self.tid == 'S00':\n                    print('t=%.3f, ZIPSH %s: strat_eval_time=%.3f,' % (time, self.tid, self.strat_eval_time))\n                    for s in self.strats:\n                        print('%s, start_t=%f, $=%f, pps=%f' %\n                              (self.strat_csv_str(s['stratvec']), s['start_t'], s['profit'], s['pps']))\n\n                # if the difference between the top two strats is too close to call then flip a coin\n                # this is to prevent the same good strat being held constant simply by chance cos it is at index [0]\n                best_strat = 0\n                prof_diff = self.strats[0]['pps'] - self.strats[1]['pps']\n                if abs(prof_diff) < self.profit_epsilon:\n                    # they're too close to call, so just flip a coin\n                    best_strat = random.randint(0, 1)\n\n                    if best_strat == 1:\n                        # need to swap strats[0] and strats[1]\n                        tmp_strat = self.strats[0]\n                        self.strats[0] = self.strats[1]\n                        self.strats[1] = tmp_strat\n\n                # at this stage, strats[0] is our newly-chosen elite-strat, about to replicate & mutate\n\n                # now replicate and mutate the elite into all the other strats\n                for s in range(1, self.k):  # note range index starts at one not zero (elite is at [0])\n                    self.strats[s]['stratvec'] = self.mutate_strat(self.strats[0]['stratvec'], 'gauss')\n                    strat_activate(time, s)\n\n                # and then update (wipe) records for the elite\n                strat_activate(time, 0)\n\n                # load the elite into the ZIP trader params\n                load_strat(self.strats[0]['stratvec'], time)\n\n                self.active_strat = 0\n\n                if vrbs and self.tid == 'S00':\n                    print('%s: strat_eval_time=%f, best_strat=%d, MUTATED:' %\n                          (self.tid, self.strat_eval_time, best_strat))\n                    for s in self.strats:\n                        print('%s start_t=%.3f, lifetime=%.3f, $=%.3f, pps=%f' %\n                              (self.strat_csv_str(s['stratvec']), s['start_t'], time - s['start_t'], s['profit'],\n                               s['pps']))\n\n            else:\n                # we're still evaluating\n\n                s = self.active_strat\n                time_elapsed = time - self.strats[s]['start_t']\n                if time_elapsed >= self.strat_wait_time:\n                    # this strategy has had long enough: update records for this strategy, then swap to another strategy\n                    self.strats[s]['active'] = False\n                    self.strats[s]['profit'] = self.balance\n                    self.strats[s]['pps'] = self.profitpertime\n                    self.strats[s]['evaluated'] = True\n\n                    new_strat = s + 1\n                    if new_strat > self.k - 1:\n                        # we've just evaluated the last of this trader's set of strategies\n                        # sort the strategies into order of descending profitability\n                        strats_sorted = sorted(self.strats, key=lambda k: k['pps'], reverse=True)\n\n                        # use this as a control: unsorts the strats, gives pure random walk.\n                        # strats_sorted = self.strats\n\n                        # the sorted list of strats replaces the existing list\n                        self.strats = strats_sorted\n\n                        # signal that we want to record a system snapshot because this trader's eval loop finished\n                        snapshot = True\n\n                        # NB not updating self.active_strat here because next call to respond() generates new popln\n\n                    else:\n                        # copy the new strategy vector into the trader's params\n                        load_strat(self.strats[new_strat]['stratvec'], time)\n                        self.strats[new_strat]['start_t'] = time\n                        self.active_strat = new_strat\n                        self.strats[new_strat]['active'] = True\n                        self.last_strat_change_time = time\n\n                    if vrbs and self.tid == 'S00':\n                        vstr = 't=%.3f (%.2fdays) %s ZIPSH respond:' % (time, time/86400, self.tid)\n                        vstr += ' strat[%d] elapsed=%.3f; wait_t=%.3f, pps=%f' % \\\n                                (s, time_elapsed, self.strat_wait_time, self.strats[s]['pps'])\n                        if new_strat > self.k - 1:\n                            print(vstr)\n                        else:\n                            vstr += ' switching to strat[%d]: %s' %\\\n                                    (new_strat, self.strat_csv_str(self.strats[new_strat]['stratvec']))\n\n        elif self.optmzr is None:\n            # this is vanilla ZIP -- nonadaptive, no optimizer, nothing to change here.\n            pass\n\n        # what, if anything, has happened on the bid LOB?\n        bid_improved = False\n        bid_hit = False\n        lob_best_bid_p = lob['bids']['best']\n        lob_best_bid_q = None\n        if lob_best_bid_p is not None:\n            # non-empty bid LOB\n            lob_best_bid_q = lob['bids']['lob'][-1][1]\n            if (self.prev_best_bid_p is not None) and (self.prev_best_bid_p < lob_best_bid_p):\n                # best bid has improved\n                # NB doesn't check if the improvement was by self\n                bid_improved = True\n            elif trade is not None and ((self.prev_best_bid_p > lob_best_bid_p) or (\n                    (self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\n                # previous best bid was hit\n                bid_hit = True\n        elif self.prev_best_bid_p is not None:\n            # the bid LOB has been emptied: was it cancelled or hit?\n            last_tape_item = lob['tape'][-1]\n            if last_tape_item['type'] == 'Cancel':\n                bid_hit = False\n            else:\n                bid_hit = True\n\n        # what, if anything, has happened on the ask LOB?\n        ask_improved = False\n        ask_lifted = False\n        lob_best_ask_p = lob['asks']['best']\n        lob_best_ask_q = None\n        if lob_best_ask_p is not None:\n            # non-empty ask LOB\n            lob_best_ask_q = lob['asks']['lob'][0][1]\n            if (self.prev_best_ask_p is not None) and (self.prev_best_ask_p > lob_best_ask_p):\n                # best ask has improved -- NB doesn't check if the improvement was by self\n                ask_improved = True\n            elif trade is not None and ((self.prev_best_ask_p < lob_best_ask_p) or (\n                    (self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\n                # trade happened and best ask price has got worse, or stayed same but quantity reduced\n                # -- assume previous best ask was lifted\n                ask_lifted = True\n        elif self.prev_best_ask_p is not None:\n            # the ask LOB is empty now but was not previously: canceled or lifted?\n            last_tape_item = lob['tape'][-1]\n            if last_tape_item['type'] == 'Cancel':\n                ask_lifted = False\n            else:\n                ask_lifted = True\n\n        if vrbs and (bid_improved or bid_hit or ask_improved or ask_lifted):\n            print('ZIP respond: B_improved', bid_improved, 'B_hit', bid_hit,\n                  'A_improved', ask_improved, 'A_lifted', ask_lifted)\n\n        deal = bid_hit or ask_lifted\n\n        if self.job == 'Ask':\n            # seller\n            if deal:\n                tradeprice = trade['price']\n                if self.price <= tradeprice:\n                    # could sell for more? raise margin\n                    target_price = target_up(tradeprice)\n                    profit_alter(target_price)\n                elif ask_lifted and self.active and not willing_to_trade(tradeprice):\n                    # wouldn't have got this deal, still working order, so reduce margin\n                    target_price = target_down(tradeprice)\n                    profit_alter(target_price)\n            else:\n                # no deal: aim for a target price higher than best bid\n                if ask_improved and self.price > lob_best_ask_p:\n                    if lob_best_bid_p is not None:\n                        target_price = target_up(lob_best_bid_p)\n                    else:\n                        target_price = lob['asks']['worst']  # stub quote\n                    profit_alter(target_price)\n\n        if self.job == 'Bid':\n            # buyer\n            if deal:\n                tradeprice = trade['price']\n                if self.price >= tradeprice:\n                    # could buy for less? raise margin (i.e. cut the price)\n                    target_price = target_down(tradeprice)\n                    profit_alter(target_price)\n                elif bid_hit and self.active and not willing_to_trade(tradeprice):\n                    # wouldn't have got this deal, still working order, so reduce margin\n                    target_price = target_up(tradeprice)\n                    profit_alter(target_price)\n            else:\n                # no deal: aim for target price lower than best ask\n                if bid_improved and self.price < lob_best_bid_p:\n                    if lob_best_ask_p is not None:\n                        target_price = target_down(lob_best_ask_p)\n                    else:\n                        target_price = lob['bids']['worst']  # stub quote\n                    profit_alter(target_price)\n\n        # remember the best LOB data ready for next response\n        self.prev_best_bid_p = lob_best_bid_p\n        self.prev_best_bid_q = lob_best_bid_q\n        self.prev_best_ask_p = lob_best_ask_p\n        self.prev_best_ask_q = lob_best_ask_q\n\n        # return value of respond() tells caller whether to print a new frame of system-snapshot data\n        return snapshot\n\n\nclass TraderPT1(Trader):\n    \"\"\"\n    A minimally simple propreitary trader that buys & sells to make profit\n\n    PT1 long-only buy-and-hold strategy in pseudocode:\n\n    1 wait until the market has been open for 5 minutes (to give prices a chance to settle)\n    2 then repeat forever:\n    2.1 if (I am not holding a unit)\n    2.1.1  and (best ask price is \"cheap\" -- i.e., less than average of recent transaction prices)\n    2.1.2  and (I have enough money in my bank to pay the asking price)\n    2.2 then\n    2.2.1   (buy the unit -- lift the ask)\n    2.2.2   (remember the purchase-price I paid for it)\n    2.3 else if (I am holding a unit)\n    2.4 then\n    2.4.1   (my asking-price is that unit’s purchase-price plus my profit margin)\n    2.4.1   if (best bid price is more than my asking price)\n    2.4.1   then\n    2.4.1.1    (sell my unit -- hit the bid)\n    2.4.1.2    (put the money in my bank)\n    \"\"\"\n\n    def __init__(self, ttype, tid, balance, params, time):\n        \"\"\"\n        Construct a PT1 trader\n        :param ttype: the ticker-symbol for the type of trader (its strategy)\n        :param tid: the trader id\n        :param balance: the trader's bank balance\n        :param params: a dictionary of optional parameter-values to override the defaults\n        :param time: the current time.\n        \"\"\"\n        \n        init_verbose = True\n        \n        Trader.__init__(self, ttype, tid, balance, params, time)\n        self.job = 'Buy'  # flag switches between 'Buy' & 'Sell'; shows what PT1 is currently trying to do\n        self.last_purchase_price = None\n\n        # Default parameter-values\n        self.n_past_trades = 5      # how many recent trades used to compute average price (avg_p)?\n        self.bid_percent = 0.9999   # what percentage of avg_p should best_ask be for this trader to bid\n        self.ask_delta = 5          # how much (absolute value) to improve on purchase price\n\n        # Did the caller provide different params?\n        if type(params) is dict:\n            if 'bid_percent' in params:\n                self.bid_percent = params['bid_percent']\n                if self.bid_percent > 1.0 or self.bid_percent < 0.01:\n                    sys.exit('FAIL: self.bid_percent=%f not in range [0.01,1.0])' % self.bid_percent)\n            if 'ask_delta' in params:\n                self.ask_delta = params['ask_delta']\n                if self.ask_delta < 0:\n                    sys.exit('Fail: PT1 ask_delta can\\'t be negative (it\\'s an absolute value)')\n            if 'n_past_trades' in params:\n                self.n_past_trades = int(round(params['n_past_trades']))\n                if self.n_past_trades < 1:\n                    sys.exit('Fail: PT1 n_past trades must be 1 or more')\n                    \n        if init_verbose:\n            print('PT1 init: n_past_trades=%d, bid_percent=%6.5f, ask_delta=%d\\n'\n                  % (self.n_past_trades, self.bid_percent, self.ask_delta))\n            \n    def getorder(self, time, countdown, lob):\n        \"\"\"\n        return this trader's order when it is polled in the main market_session loop.\n        :param time: the current time.\n        :param countdown: the time remaining until market closes (not currently used).\n        :param lob: the public lob.\n        :return: trader's new order, or None.\n        \"\"\"\n        # this test for negative countdown is purely to stop PyCharm warning about unused parameter value\n        if countdown < 0:\n            sys.exit('Negative countdown')\n\n        if len(self.orders) < 1 or time < 5 * 60:\n            order = None\n        else:\n            quoteprice = self.orders[0].price\n            order = Order(self.tid,\n                          self.orders[0].otype,\n                          quoteprice,\n                          self.orders[0].qty,\n                          time, lob['QID'])\n            self.lastquote = order\n        return order\n\n    def respond(self, time, lob, trade, vrbs):\n        \"\"\"\n        Respond to the current state of the public lob.\n        Buys if best bid is less than simple moving average of recent transcaction prices.\n        Sells as soon as it can make an acceptable profit.\n        :param time: the current time\n        :param lob: the current public lob\n        :param trade:\n        :param vrbs: verbosity -- if True then print running commentary, else stay silent\n        :return: <nothing>\n        \"\"\"\n\n        vstr = 't=%f PT1 respond: ' % time\n\n        # what is average price of most recent n trades?\n        # work backwards from end of tape (most recent trade)\n        tape_position = -1\n        n_prices = 0\n        sum_prices = 0\n        avg_price_ok = False\n        avg_price = -1\n        while n_prices < self.n_past_trades and abs(tape_position) < len(lob['tape']):\n            if lob['tape'][tape_position]['type'] == 'Trade':\n                price = lob['tape'][tape_position]['price']\n                n_prices += 1\n                sum_prices += price\n            tape_position -= 1\n        if n_prices == self.n_past_trades:\n            # there's been enough trades to form an acceptable average\n            avg_price = int(round(sum_prices / n_prices))\n            avg_price_ok = True\n        vstr += \"avg_price_ok=%s, avg_price=%d \" % (avg_price_ok, avg_price)\n\n        # buying?\n        if self.job == 'Buy' and avg_price_ok:\n            vstr += 'Buying - '\n            # see what's on the LOB\n            if lob['asks']['n'] > 0:\n                # there is at least one ask on the LOB\n                best_ask = lob['asks']['best']\n                if best_ask / avg_price < self.bid_percent:\n                    # bestask is good value: send a spread-crossing bid to lift the ask\n                    bidprice = best_ask + 1\n                    if bidprice < self.balance:\n                        # can afford to buy\n                        # create the bid by issuing order to self, which will be processed in getorder()\n                        order = Order(self.tid, 'Bid', bidprice, 1, time, lob['QID'])\n                        self.orders = [order]\n                        vstr += 'Best ask=%d, bidprice=%d, order=%s ' % (best_ask, bidprice, order)\n                else:\n                    vstr += 'bestask=%d >= avg_price=%d' % (best_ask, avg_price)\n            else:\n                vstr += 'No asks on LOB'\n        # selling?\n        elif self.job == 'Sell':\n            vstr += 'Selling - '\n            # see what's on the LOB\n            if lob['bids']['n'] > 0:\n                # there is at least one bid on the LOB\n                best_bid = lob['bids']['best']\n                # sell single unit at price of purchaseprice+askdelta\n                askprice = self.last_purchase_price + self.ask_delta\n                if askprice < best_bid:\n                    # seems we have a buyer\n                    # lift the ask by issuing order to self, which will processed in getorder()\n                    order = Order(self.tid, 'Ask', askprice, 1, time, lob['QID'])\n                    self.orders = [order]\n                    vstr += 'Best bid=%d greater than askprice=%d order=%s ' % (best_bid, askprice, order)\n                else:\n                    vstr += 'Best bid=%d too low for askprice=%d ' % (best_bid, askprice)\n            else:\n                vstr += 'No bids on LOB'\n\n        self.profitpertime = self.profitpertime_update(time, self.birthtime, self.balance)\n\n        if vrbs:\n            print(vstr)\n\n    def bookkeep(self, time, trade, order, vrbs):\n        \"\"\"\n        Update trader's records of its bank balance, current orders, and current job\n        :param trade: the current time\n        :param order: this trader's successful order\n        :param vrbs: verbosity -- if True then print running commentary, else stay silent.\n        :param time: the current time.\n        :return: <nothing>\n        \"\"\"\n\n        # output string outstr is printed if vrbs==True\n        mins = int(time//60)\n        secs = time - 60 * mins\n        hrs = int(mins//60)\n        mins = mins - 60 * hrs\n        outstr = 't=%f (%dh%02dm%02ds) %s (%s) bookkeep: orders=' % (time, hrs, mins, secs, self.tid, self.ttype)\n        for order in self.orders:\n            outstr = outstr + str(order)\n\n        self.blotter.append(trade)  # add trade record to trader's blotter\n\n        # NB What follows is **LAZY** -- assumes all orders are quantity=1\n        transactionprice = trade['price']\n        if self.orders[0].otype == 'Bid':\n            # Bid order succeeded, remember the price and adjust the balance\n            self.balance -= transactionprice\n            self.last_purchase_price = transactionprice\n            self.job = 'Sell'  # now try to sell it for a profit\n        elif self.orders[0].otype == 'Ask':\n            # Sold! put the money in the bank\n            self.balance += transactionprice\n            self.last_purchase_price = 0\n            self.job = 'Buy'  # now go back and buy another one\n        else:\n            sys.exit('FATAL: PT1 doesn\\'t know .otype %s\\n' % self.orders[0].otype)\n\n        if vrbs:\n            net_worth = self.balance + self.last_purchase_price\n            print('%s Balance=%d NetWorth=%d' % (outstr, self.balance, net_worth))\n\n        self.del_order(order)  # delete the order\n\n    # end of PT1 definition\n\n\nclass TraderPT2(Trader):\n    \"\"\"\n    A A minimally simple propreitary trader that buys & sells to make profit\n\n    PT2 long-only buy-and-hold strategy in pseudocode:\n\n    1 wait until the market has been open for 5 minutes (to give prices a chance to settle)\n    2 then repeat forever:\n    2.1 if (I am not holding a unit)\n    2.1.1  and (best ask price is \"cheap\" -- i.e., less than average of recent transaction prices)\n    2.1.2  and (I have enough money in my bank to pay the asking price)\n    2.2 then\n    2.2.1   (buy the unit -- lift the ask)\n    2.2.2   (remember the purchase-price I paid for it)\n    2.3 else if (I am holding a unit)\n    2.4 then\n    2.4.1   (my asking-price is that unit’s purchase-price plus my profit margin)\n    2.4.1   if (best bid price is more than my asking price)\n    2.4.1   then\n    2.4.1.1    (sell my unit -- hit the bid)\n    2.4.1.2    (put the money in my bank)\n    \"\"\"\n\n    def __init__(self, ttype, tid, balance, params, time):\n        \"\"\"\n        Construct a PT2 trader\n        :param ttype: the ticker-symbol for the type of trader (its strategy)\n        :param tid: the trader id\n        :param balance: the trader's bank balance\n        :param params: a dictionary of optional parameter-values to override the defaults\n        :param time: the current time.\n        \"\"\"\n\n        Trader.__init__(self, ttype, tid, balance, params, time)\n        self.job = 'Buy'  # flag switches between 'Buy' & 'Sell'; shows what PT2 is currently trying to do\n        self.last_purchase_price = None\n        \n        init_verbose = True\n\n        # Default parameter-values\n        self.n_past_trades = 5      # how many recent trades used to compute average price (avg_p)?\n        self.bid_percent = 0.9999   # what percentage of avg_p should best_ask be for this trader to bid\n        self.ask_delta = 5          # how much (absolute value) to improve on purchase price\n\n        # Did the caller provide different params?\n        if type(params) is dict:\n            if 'bid_percent' in params:\n                self.bid_percent = params['bid_percent']\n                if self.bid_percent > 1.0 or self.bid_percent < 0.01:\n                    sys.exit('FAIL: PT2 self.bid_percent=%f not in range [0.01,1.0])' % self.bid_percent)\n            if 'ask_delta' in params:\n                self.ask_delta = params['ask_delta']\n                if self.ask_delta < 0:\n                    sys.exit('Fail: PT2 ask_delta can\\'t be negative (it\\'s an absolute value)')\n            if 'n_past_trades' in params:\n                self.n_past_trades = int(round(params['n_past_trades']))\n                if self.n_past_trades < 1:\n                    sys.exit('Fail: PT2 n_past trades must be 1 or more')\n                    \n        if init_verbose:\n            print('PT2 init: n_past_trades=%d, bid_percent=%6.5f, ask_delta=%d\\n'\n                  % (self.n_past_trades, self.bid_percent, self.ask_delta))\n\n    def getorder(self, time, countdown, lob):\n        \"\"\"\n        return this trader's order when it is polled in the main market_session loop.\n        :param time: the current time.\n        :param countdown: the time remaining until market closes (not currently used).\n        :param lob: the public lob.\n        :return: trader's new order, or None.\n        \"\"\"\n        # this test for negative countdown is purely to stop PyCharm warning about unused parameter value\n        if countdown < 0:\n            sys.exit('Negative countdown')\n\n        if len(self.orders) < 1 or time < 5 * 60:\n            order = None\n        else:\n            quoteprice = self.orders[0].price\n            order = Order(self.tid,\n                          self.orders[0].otype,\n                          quoteprice,\n                          self.orders[0].qty,\n                          time, lob['QID'])\n            self.lastquote = order\n        return order\n\n    def respond(self, time, lob, trade, vrbs):\n        \"\"\"\n        Respond to the current state of the public lob.\n        Buys if best bid is less than simple moving average of recent transcaction prices.\n        Sells as soon as it can make an acceptable profit.\n        :param time: the current time\n        :param lob: the current public lob\n        :param trade:\n        :param vrbs: if True then print running commentary, else stay silent\n        :return: <nothing>\n        \"\"\"\n\n        vstr = 't=%f PT2 respond: ' % time\n\n        # what is average price of most recent n trades?\n        # work backwards from end of tape (most recent trade)\n        tape_position = -1\n        n_prices = 0\n        sum_prices = 0\n        avg_price_ok = False\n        avg_price = -1\n        while n_prices < self.n_past_trades and abs(tape_position) < len(lob['tape']):\n            if lob['tape'][tape_position]['type'] == 'Trade':\n                price = lob['tape'][tape_position]['price']\n                n_prices += 1\n                sum_prices += price\n            tape_position -= 1\n        if n_prices == self.n_past_trades:\n            # there's been enough trades to form an acceptable average\n            avg_price = int(round(sum_prices / n_prices))\n            avg_price_ok = True\n        vstr += \"avg_price_ok=%s, avg_price=%d \" % (avg_price_ok, avg_price)\n\n        # buying?\n        if self.job == 'Buy' and avg_price_ok:\n            vstr += 'Buying - '\n            # see what's on the LOB\n            if lob['asks']['n'] > 0:\n                # there is at least one ask on the LOB\n                best_ask = lob['asks']['best']\n                if best_ask / avg_price < self.bid_percent:\n                    # bestask is good value: send a spread-crossing bid to lift the ask\n                    bidprice = best_ask + 1\n                    if bidprice < self.balance:\n                        # can afford to buy\n                        # create the bid by issuing order to self, which will be processed in getorder()\n                        order = Order(self.tid, 'Bid', bidprice, 1, time, lob['QID'])\n                        self.orders = [order]\n                        vstr += 'Best ask=%d, bidprice=%d, order=%s ' % (best_ask, bidprice, order)\n                else:\n                    vstr += 'bestask=%d >= avg_price=%d' % (best_ask, avg_price)\n            else:\n                vstr += 'No asks on LOB'\n        # selling?\n        elif self.job == 'Sell':\n            vstr += 'Selling - '\n            # see what's on the LOB\n            if lob['bids']['n'] > 0:\n                # there is at least one bid on the LOB\n                best_bid = lob['bids']['best']\n                # sell single unit at price of purchaseprice+askdelta\n                askprice = self.last_purchase_price + self.ask_delta\n                if askprice < best_bid:\n                    # seems we have a buyer\n                    # lift the ask by issuing order to self, which will processed in getorder()\n                    order = Order(self.tid, 'Ask', askprice, 1, time, lob['QID'])\n                    self.orders = [order]\n                    vstr += 'Best bid=%d greater than askprice=%d order=%s ' % (best_bid, askprice, order)\n                else:\n                    vstr += 'Best bid=%d too low for askprice=%d ' % (best_bid, askprice)\n            else:\n                vstr += 'No bids on LOB'\n\n        self.profitpertime = self.profitpertime_update(time, self.birthtime, self.balance)\n\n        if vrbs:\n            print(vstr)\n\n    def bookkeep(self, time, trade, order, vrbs):\n        \"\"\"\n        Update trader's records of its bank balance, current orders, and current job\n        :param trade: the current time\n        :param order: this trader's successful order\n        :param vrbs: if True then print a running commentary, otherwise stay silent.\n        :param time: the current time.\n        :return: <nothing>\n        \"\"\"\n\n        # output string outstr is printed if vrbs==True\n        mins = int(time//60)\n        secs = time - 60 * mins\n        hrs = int(mins//60)\n        mins = mins - 60 * hrs\n        outstr = 't=%f (%dh%02dm%02ds) %s (%s) bookkeep: orders=' % (time, hrs, mins, secs, self.tid, self.ttype)\n        for order in self.orders:\n            outstr = outstr + str(order)\n\n        self.blotter.append(trade)  # add trade record to trader's blotter\n\n        # NB What follows is **LAZY** -- assumes all orders are quantity=1\n        transactionprice = trade['price']\n        if self.orders[0].otype == 'Bid':\n            # Bid order succeeded, remember the price and adjust the balance\n            self.balance -= transactionprice\n            self.last_purchase_price = transactionprice\n            self.job = 'Sell'  # now try to sell it for a profit\n        elif self.orders[0].otype == 'Ask':\n            # Sold! put the money in the bank\n            self.balance += transactionprice\n            self.last_purchase_price = 0\n            self.job = 'Buy'  # now go back and buy another one\n        else:\n            sys.exit('FATAL: PT2 doesn\\'t know .otype %s\\n' % self.orders[0].otype)\n\n        if vrbs:\n            net_worth = self.balance + self.last_purchase_price\n            print('%s Balance=%d NetWorth=%d' % (outstr, self.balance, net_worth))\n\n        self.del_order(order)  # delete the order\n\n    # end of PT2 definition\n\n# ########################---trader-types have all been defined now--################\n\n\n# #########################---Below lies the experiment/test-rig---##################\n\n\ndef trade_stats(expid, traders, dumpfile, time, lob):\n    \"\"\"\n    Dump CSV statistics on exchange data and trader population to file for later analysis.\n    This makes no assumptions about the number of types of traders, or the number of traders of any one type\n    -- allows either/both to change between successive calls, but that does make it inefficient as it has to\n    re-analyse the entire set of traders on each call.\n    :param expid: the experiment-I.D. character-string.\n    :param traders: the list of traders in the market.\n    :param dumpfile: the file that will be written to.\n    :param time: the current time.\n    :param lob: the current state of the LOB.\n    :return: <nothing>\n    \"\"\"\n\n    # Analyse the set of traders, to see what types we have\n    trader_types = {}\n    for t in traders:\n        ttype = traders[t].ttype\n        if ttype in trader_types.keys():\n            t_balance = trader_types[ttype]['balance_sum'] + traders[t].balance\n            n = trader_types[ttype]['n'] + 1\n        else:\n            t_balance = traders[t].balance\n            n = 1\n        trader_types[ttype] = {'n': n, 'balance_sum': t_balance}\n\n    # first two columns of output are the session_id and the time\n    dumpfile.write('%s, %06d, ' % (expid, time))\n\n    # second two columns of output are the LOB best bid and best offer (or 'None' if they're undefined)\n    if lob['bids']['best'] is not None:\n        dumpfile.write('%d, ' % (lob['bids']['best']))\n    else:\n        dumpfile.write('None, ')\n    if lob['asks']['best'] is not None:\n        dumpfile.write('%d, ' % (lob['asks']['best']))\n    else:\n        dumpfile.write('None, ')\n\n    # total remaining number of columns printed depends on number of different trader-types at this timestep\n    # for each trader type we print FOUR columns...\n    # TraderTypeCode, TotalProfitForThisTraderType, NumberOfTradersOfThisType, AverageProfitPerTraderOfThisType\n    for ttype in sorted(list(trader_types.keys())):\n        n = trader_types[ttype]['n']\n        s = trader_types[ttype]['balance_sum']\n        dumpfile.write('%s, %d, %d, %f, ' % (ttype, s, n, s / float(n)))\n\n    dumpfile.write('\\n')\n\n\ndef populate_market(trdrs_spec, traders, shuffle, vrbs):\n    \"\"\"\n    Create a bunch of traders from traders-specification.\n    Optionally shuffles the pack of buyers and the pack of sellers.\n    :param trdrs_spec: the specification of the population of traders.\n    :param traders: the list into which the newly-created traders traders will be written, as a return parameter\n    :param shuffle: whether to shuffle the ordering of buyers/sellers within the respective list.\n    :param vrbs: verbosity Boolean: if True, print a running commentary; if False, stay silent.\n    :return: tuple (n_buyers, n_sellers)\n    \"\"\"\n    # trdrs_spec is a list of buyer-specs and a list of seller-specs\n    # each spec is (<trader type>, <number of this type of trader>, optionally: <params for this type of trader>)\n\n    def trader_type(robottype, name, parameters):\n        \"\"\"\n        Create a newly instantiated trader of the designated type.\n        :param robottype: the 'ticker-symbol' abbreviation indicating what type of trader to create.\n        :param name: this trader's trader-I.D. character string.\n        :param parameters: a list of parameter values for this trader-type.\n        :return: a newly created trader of the designated type.\n        \"\"\"\n        balance = 0.00\n        proptrader_balance = 500  # marketmakers start with zero inventory and a balance of $500\n        time0 = 0\n        if robottype == 'GVWY':\n            return TraderGiveaway('GVWY', name, balance, parameters, time0)\n        elif robottype == 'ZIC':\n            return TraderZIC('ZIC', name, balance, parameters, time0)\n        elif robottype == 'SHVR':\n            return TraderShaver('SHVR', name, balance, parameters, time0)\n        elif robottype == 'SNPR':\n            return TraderSniper('SNPR', name, balance, parameters, time0)\n        elif robottype == 'ZIP':\n            return TraderZIP('ZIP', name, balance, parameters, time0)\n        elif robottype == 'ZIPSH':\n            return TraderZIP('ZIPSH', name, balance, parameters, time0)\n        elif robottype == 'PRZI':\n            return TraderPRZI('PRZI', name, balance, parameters, time0)\n        elif robottype == 'PRSH':\n            return TraderPRZI('PRSH', name, balance, parameters, time0)\n        elif robottype == 'PRDE':\n            return TraderPRZI('PRDE', name, balance, parameters, time0)\n        elif robottype == 'PT1':\n            return TraderPT1('PT1', name, proptrader_balance, parameters, time0)\n        elif robottype == 'PT2':\n            return TraderPT2('PT2', name, proptrader_balance, parameters, time0)\n        else:\n            sys.exit('FATAL: don\\'t know trader type %s\\n' % robottype)\n\n    def shuffle_traders(ttype_char, n, trader_list):\n        \"\"\"\n        Shuffles the trader-I.D. character strings of the traders in trader_list\n        :param ttype_char: the lead character on the trader-I.D. strings (B for buyer, S for seller, etc)\n        :param n: how many traders of this type\n        :param trader_list: the list of traders in which the shuffling happens\n        :return: <nothing>\n        \"\"\"\n        for swap in range(n):\n            t1 = (n - 1) - swap\n            t2 = random.randint(0, t1)\n            t1name = '%c%02d' % (ttype_char, t1)\n            t2name = '%c%02d' % (ttype_char, t2)\n            trader_list[t1name].tid = t2name\n            trader_list[t2name].tid = t1name\n            temp = traders[t1name]\n            trader_list[t1name] = trader_list[t2name]\n            trader_list[t2name] = temp\n\n    def unpack_params(trader_params, mapping):\n        \"\"\"\n        Unpack the parameters for those trader-types that have them\n        :param trader_params: the paramaters being passed to this trader.\n        :param mapping: Boolean flag: if True, enable fitness-landscape-mapping; otherwise do nothing for mapping.\n        :return: the dictionary of parameters for this trader.\n        \"\"\"\n\n        parameters = None\n\n        if ttype == 'ZIPSH' or ttype == 'ZIP':\n            # parameters matter...\n            if mapping:\n                parameters = 'landscape-mapper'\n            elif trader_params is not None:\n                parameters = trader_params.copy()\n                # trader-type determines type of optimizer used\n                if ttype == 'ZIPSH':\n                    parameters['optimizer'] = 'ZIPSH'\n                else:   # ttype=ZIP\n                    parameters['optimizer'] = None\n        if ttype == 'PRSH' or ttype == 'PRDE' or ttype == 'PRZI':\n            # parameters matter...\n            if mapping:\n                parameters = 'landscape-mapper'\n            elif trader_params is not None:\n                # params determines type of optimizer used\n                if ttype == 'PRSH':\n                    parameters = {'optimizer': 'PRSH', 'k': trader_params['k'],\n                                  'strat_min': trader_params['s_min'], 'strat_max': trader_params['s_max']}\n                elif ttype == 'PRDE':\n                    parameters = {'optimizer': 'PRDE', 'k': trader_params['k'],\n                                  'strat_min': trader_params['s_min'], 'strat_max': trader_params['s_max']}\n                else:   # ttype=PRZI\n                    parameters = {'optimizer': None, 'k': 1,\n                                  'strat_min': trader_params['s_min'], 'strat_max': trader_params['s_max']}\n            else:\n                sys.exit('FAIL: PRZI/PRSH/PRDE trader needs one or more parameters to be specified')\n                \n        # for PT1/PT2 the parameters are optional...\n        # ...and are unpacked in __init__, so here they're just passed straight on through\n        if ttype == 'PT1':\n            parameters = trader_params\n        if ttype == 'PT2':\n            parameters = trader_params\n\n        return parameters\n\n    landscape_mapping = False   # set to true when mapping fitness landscape (for PRSH etc).\n\n    # the code that follows is a bit of a kludge, needs tidying up.\n    n_buyers = 0\n    for bs in trdrs_spec['buyers']:\n        ttype = bs[0]\n        for b in range(bs[1]):\n            tname = 'B%02d' % n_buyers  # buyer i.d. string\n            if len(bs) > 2:\n                # third part of the buyer-spec is params for this trader-type\n                params = unpack_params(bs[2], landscape_mapping)\n            else:\n                params = unpack_params(None, landscape_mapping)\n            traders[tname] = trader_type(ttype, tname, params)\n            n_buyers = n_buyers + 1\n\n    if n_buyers < 1:\n        sys.exit('FATAL: no buyers specified\\n')\n\n    if shuffle:\n        shuffle_traders('B', n_buyers, traders)\n\n    n_sellers = 0\n    for ss in trdrs_spec['sellers']:\n        ttype = ss[0]\n        for s in range(ss[1]):\n            tname = 'S%02d' % n_sellers  # buyer i.d. string\n            if len(ss) > 2:\n                # third part of the buyer-spec is params for this trader-type\n                params = unpack_params(ss[2], landscape_mapping)\n            else:\n                params = unpack_params(None, landscape_mapping)\n            traders[tname] = trader_type(ttype, tname, params)\n            n_sellers = n_sellers + 1\n\n    if n_sellers < 1:\n        sys.exit('FATAL: no sellers specified\\n')\n\n    if shuffle:\n        shuffle_traders('S', n_sellers, traders)\n\n    n_proptraders = 0\n    if 'proptraders' in trdrs_spec and len(trdrs_spec['proptraders']) > 0:\n        for pts in trdrs_spec['proptraders']:\n            ttype = pts[0]\n            for pt in range(pts[1]):\n                tname = 'P%02d' % n_proptraders  # proptrader i.d. string\n                if len(pts) > 2:\n                    # third part of the buyer-spec is params for this trader-type\n                    params = unpack_params(pts[2], landscape_mapping)\n                else:\n                    params = unpack_params(None, landscape_mapping)\n                traders[tname] = trader_type(ttype, tname, params)\n                n_proptraders = n_proptraders + 1\n\n    # NB markets with zero proptraders don't cause a fatal error\n\n    if n_proptraders > 0 and shuffle:\n        shuffle_traders('P', n_proptraders, traders)\n\n    if vrbs:\n        for t in range(n_buyers):\n            tname = 'B%02d' % t\n            print(traders[tname])\n        for t in range(n_sellers):\n            tname = 'S%02d' % t\n            print(traders[tname])\n        for t in range(n_proptraders):\n            tname = 'P%02d' % t\n            print(traders[tname])\n\n    return {'n_buyers': n_buyers, 'n_sellers': n_sellers, 'n_proptraders': n_proptraders}\n\n\ndef customer_orders(time, traders, trader_stats, orders_sched, pending, vrbs):\n    \"\"\"\n    Generate a list of new customer-orders to be issued to the traders in the immediate/near future,\n    and a list of any existing customer-orders that need to be cancelled because they are overridden by new ones.\n    :param time: the current time.\n    :param traders: the population of traders.\n    :param trader_stats: summary statistics about the population of traders.\n    :param orders_sched: the supply/demand schedule from which the orders will be generated...\n            os['timemode'] is either 'periodic', 'drip-fixed', 'drip-jitter', or 'drip-poisson';\n            os['interval'] is number of seconds for a full cycle of replenishment;\n            drip-poisson sequences will be normalised to ensure time of last replenishment <= interval.\n            If a supply or demand schedule mode is \"random\" and more than one range is supplied in ranges[],\n            then each time a price is generated one of the ranges is chosen equiprobably and the price is\n            then generated uniform-randomly from that range.\n            if len(range)==2, interpreted as min and max values on the schedule, specifying linear supply/demand curve.\n            if len(range)==3, first two vals are min & max for linear sup/dem curves, and third value should be a\n            callable function that generates a dynamic price offset; he offset value applies equally to the min & max,\n            so gradient of linear sup/dem curves doesn't vary, but equilibrium price does.\n            if len(range)==4, the third value is function that gives dynamic offset for schedule min, and 4th is a\n            function giving dynamic offset for schedule max, so gradient of sup/dem linear curve can vary dynamically\n            along with the varying equilibrium price.\n    :param pending: the list of currently pending future orders if this is empty, generates a new one).\n    :param vrbs: verbosity Boolean: if True, print a running commentary; if False, stay silent.\n    :return: [new_pending, cancellations]:\n            new_pending is list of new orders to be issued;\n            cancellations is list of previously-issued orders now cancelled.\n    \"\"\"\n\n    def sysmin_check(price):\n        \"\"\" if price is less than system minimum price, issue a warning and clip the price to the minimum\"\"\"\n        if price < bse_sys_minprice:\n            print('WARNING: price < bse_sys_min -- clipped')\n            price = bse_sys_minprice\n        return price\n\n    def sysmax_check(price):\n        \"\"\" if price is greater than system maximum price, issue a warning and clip the price to the maximum\"\"\"\n        if price > bse_sys_maxprice:\n            print('WARNING: price > bse_sys_max -- clipped')\n            price = bse_sys_maxprice\n        return price\n\n    def getorderprice(i, schedules, n, stepmode, orderissuetime):\n        \"\"\"\n        Generate a price for an order, using the given supply/demand schedule, and specified step-mode.\n        :param i: index of trader (position in list of traders).\n        :param schedules: the supply/demand schedules.\n        :param n: the number of traders that this schedule sup/dem is being applied to.\n        :param stepmode: what type of steps to have between successive prices on the sup/dem schedule.\n                stepmode=='fixed' => all steps are equal at one fixed size -- a \"uniform-step\" (see \"jittered\", below);\n                stepmode=='jittered' => all steps are random, constrained to be within 2 uniform-steps of each other;\n                stepmode=='random' => all steps are generated from a uniform distribution.\n        :param orderissuetime: the time that this order will be issued at.\n        :return: the price.\n        \"\"\"\n\n        # does the first schedule range include optional dynamic offset function(s)?\n        if len(schedules[0]) > 2:\n            offsetfn = schedules[0][2]\n            if callable(offsetfn[0]):\n                # same offset for min and max\n                offset_min = offsetfn[0](orderissuetime, *offsetfn[1])\n                offset_max = offset_min\n            else:\n                sys.exit('FAIL: 3rd argument of sched in getorderprice() not callable')\n            if len(schedules[0]) > 3:\n                # if second offset function is specified, that applies only to the max value\n                offsetfn = schedules[0][3]\n                if callable(offsetfn):\n                    # this function applies to max\n                    offset_max = offsetfn(orderissuetime)\n                else:\n                    sys.exit('FAIL: 4th argument of sched in getorderprice() not callable')\n        else:\n            offset_min = 0.0\n            offset_max = 0.0\n\n        pmin = sysmin_check(offset_min + min(schedules[0][0], schedules[0][1]))\n        pmax = sysmax_check(offset_max + max(schedules[0][0], schedules[0][1]))\n        prange = pmax - pmin\n        stepsize = prange / (n - 1)\n        halfstep = round(stepsize / 2.0)\n\n        if stepmode == 'fixed':\n            order_price = pmin + int(i * stepsize)\n        elif stepmode == 'jittered':\n            order_price = pmin + int(i * stepsize) + random.randint(-halfstep, halfstep)\n        elif stepmode == 'random':\n            if len(schedules) > 1:\n                # more than one schedule: choose one equiprobably\n                s = random.randint(0, len(schedules) - 1)\n                pmin = sysmin_check(min(schedules[s][0], schedules[s][1]))\n                pmax = sysmax_check(max(schedules[s][0], schedules[s][1]))\n            order_price = random.randint(int(pmin), int(pmax))\n        else:\n            sys.exit('FAIL: Unknown mode in schedule')\n        order_price = sysmin_check(sysmax_check(order_price))\n        return order_price\n\n    def getissuetimes(n_traders, timemode, interval, shuffle, fittointerval):\n        \"\"\"\n        Generate a list of issue/arrival times for a set of future customer-orders, over a specified time-interval.\n        :param n_traders: how many traders need issue times (i.e., the number of customer orders to be generated)\n        :param timemode: character-string specifying the temporal spacing of orders:\n                timemode=='periodic'=> orders issued to all traders at the same instant in time, every time-interval;\n                timemode=='drip-fixed'=> order interarrival time is exactly one timestep, for all orders;\n                timemode=='drip-jitter'=> order interarrival time is (1+r)*timestep, r=U[0,timestep], for all orders;\n                timemode=='drip-poisson'=> order interarrival time is a Poisson random process, for all orders.\n        :param interval: the time-interval between successive order issuals/arrivals.\n        :param shuffle: if True then shuffle the arrival times, randomising the sequence in which traders get orders.\n        :param fittointerval: if True then final order arrives at exactly t+interval; else may be slightly later.\n        :return: the list of issue times.\n        \"\"\"\n        interval = float(interval)\n        if n_traders < 1:\n            sys.exit('FAIL: n_traders < 1 in getissuetime()')\n        elif n_traders == 1:\n            tstep = interval\n        else:\n            tstep = interval / (n_traders - 1)\n        arrtime = 0\n        issue_times = []\n        for trdr in range(n_traders):\n            if timemode == 'periodic':\n                arrtime = interval\n            elif timemode == 'drip-fixed':\n                arrtime = trdr * tstep\n            elif timemode == 'drip-jitter':\n                arrtime = trdr * tstep + tstep * random.random()\n            elif timemode == 'drip-poisson':\n                # poisson requires a bit of extra work\n                interarrivaltime = random.expovariate(n_traders / interval)\n                arrtime += interarrivaltime\n            else:\n                sys.exit('FAIL: unknown time-mode in getissuetimes()')\n            issue_times.append(arrtime)\n            # at this point, arrtime is the last arrival time\n\n        if fittointerval and ((arrtime > interval) or (arrtime < interval)):\n            # generated sum of interarrival times longer than the interval\n            # squish them back so that last arrival falls at t=interval\n            for trdr in range(n_traders):\n                issue_times[trdr] = interval * (issue_times[trdr] / arrtime)\n        # optionally randomly shuffle the times\n        if shuffle:\n            for trdr in range(n_traders):\n                i = (n_traders - 1) - trdr\n                j = random.randint(0, i)\n                tmp = issue_times[i]\n                issue_times[i] = issue_times[j]\n                issue_times[j] = tmp\n        return issue_times\n\n    def getschedmode(t_now, order_schedules):\n        \"\"\"\n        return the step-mode for supply/demand schedule at the current time\n        :param t_now: the current time\n        :param order_schedules: dictionary/list of order schedules\n        :return: schedrange = the price range for this schedule; mode= the stepmode for this schedule\n        \"\"\"\n        got_one = False\n        schedrange = None\n        stepmode = None\n        for schedule in order_schedules:\n            if (schedule['from'] <= t_now) and (t_now < schedule['to']):\n                # within the timezone for this schedule\n                schedrange = schedule['ranges']\n                stepmode = schedule['stepmode']\n                got_one = True\n                break  # jump out the loop -- so the first matching timezone has priority over any others\n        if not got_one:\n            sys.exit('Fail: time=%5.2f not within any timezone in order_schedules=%s' % (t_now, order_schedules))\n        return schedrange, stepmode\n\n    n_buyers = trader_stats['n_buyers']\n    n_sellers = trader_stats['n_sellers']\n\n    shuffle_times = True\n\n    cancellations = []\n\n    if len(pending) < 1:\n        # list of pending (to-be-issued) customer orders is empty, so generate a new one\n        new_pending = []\n\n        # demand side (buyers)\n        issuetimes = getissuetimes(n_buyers, orders_sched['timemode'], orders_sched['interval'], shuffle_times, True)\n\n        ordertype = 'Bid'\n        (sched, mode) = getschedmode(time, orders_sched['dem'])\n        for t in range(n_buyers):\n            issuetime = time + issuetimes[t]\n            tname = 'B%02d' % t\n            orderprice = getorderprice(t, sched, n_buyers, mode, issuetime)\n            order = Order(tname, ordertype, orderprice, 1, issuetime, chrono.time())\n            new_pending.append(order)\n\n        # supply side (sellers)\n        issuetimes = getissuetimes(n_sellers, orders_sched['timemode'], orders_sched['interval'], shuffle_times, True)\n        ordertype = 'Ask'\n        (sched, mode) = getschedmode(time, orders_sched['sup'])\n        for t in range(n_sellers):\n            issuetime = time + issuetimes[t]\n            tname = 'S%02d' % t\n            orderprice = getorderprice(t, sched, n_sellers, mode, issuetime)\n            # print('time %d sellerprice %d' % (time,orderprice))\n            order = Order(tname, ordertype, orderprice, 1, issuetime, chrono.time())\n            new_pending.append(order)\n    else:\n        # there are pending future orders: issue any whose timestamp is in the past\n        new_pending = []\n        for order in pending:\n            if order.time < time:\n                # this order should have been issued by now\n                # issue it to the trader\n                tname = order.tid\n                response = traders[tname].add_order(order, vrbs)\n                if vrbs:\n                    print('Customer order: %s %s' % (response, order))\n                if response == 'LOB_Cancel':\n                    cancellations.append(tname)\n                    if vrbs:\n                        print('Cancellations: %s' % cancellations)\n                # and then don't add it to new_pending (i.e., delete it)\n            else:\n                # this order stays on the pending list\n                new_pending.append(order)\n    return [new_pending, cancellations]\n\n\ndef market_session(sess_id, starttime, endtime, trader_spec, order_schedule, dumpfile_flags, sess_vrbs):\n    \"\"\"\n    One session in the market.\n    :param sess_id: the character-string ID for this session, used in naming output files.\n    :param starttime: the time the session starts.\n    :param endtime: the time the sessiom ends.\n    :param trader_spec: specification of the traders populating the market for this session.\n    :param order_schedule: specification of the \"customer orders\" assigned to traders, i.e. the supply/demand schedule.\n    :param dumpfile_flags: a dictionary of Boolean flags specifying which output files to be written for this session.\n    :param sess_vrbs: verbosity: if True, output a running commentary on what is going on; if False, stay silent.\n    :return: <nothing>.\n    \"\"\"\n\n    def dump_strats_frame(frametime, stratfile, trdrs):\n        \"\"\"\n        Write one frame of strategy snapshot\n        :param frametime: the time that the frame snapshot is printed.\n        :param stratfile:  the file to write to.\n        :param trdrs: the population of traders.\n        :return: <nothing>\n        \"\"\"\n\n        line_str = 't=,%.0f, ' % frametime\n\n        best_buyer_id = None\n        best_buyer_prof = 0\n        best_buyer_strat = None\n        best_seller_id = None\n        best_seller_prof = 0\n        best_seller_strat = None\n\n        # loop through traders to find the best\n        for trdr in traders:\n            trader = trdrs[trdr]\n\n            # print('PRSH/PRDE/ZIPSH strategy recording, t=%s' % trader)\n            if trader.ttype == 'PRSH' or trader.ttype == 'PRDE' or trader.ttype == 'ZIPSH':\n                line_str += 'id=,%s, %s,' % (trader.tid, trader.ttype)\n\n                if trader.ttype == 'ZIPSH':\n                    # we know that ZIPSH sorts the set of strats into best-first\n                    act_strat = trader.strats[0]['stratvec']\n                    act_prof = trader.strats[0]['pps']\n                else:\n                    act_strat = trader.strats[trader.active_strat]['stratval']\n                    act_prof = trader.strats[trader.active_strat]['pps']\n\n                line_str += 'actvstrat=,%s ' % trader.strat_csv_str(act_strat)\n                line_str += 'actvprof=,%f, ' % act_prof\n\n                if trader.tid[:1] == 'B':\n                    # this trader is a buyer\n                    if best_buyer_id is None or act_prof > best_buyer_prof:\n                        best_buyer_id = trader.tid\n                        best_buyer_strat = act_strat\n                        best_buyer_prof = act_prof\n                elif trader.tid[:1] == 'S':\n                    # this trader is a seller\n                    if best_seller_id is None or act_prof > best_seller_prof:\n                        best_seller_id = trader.tid\n                        best_seller_strat = act_strat\n                        best_seller_prof = act_prof\n                else:\n                    # wtf?\n                    sys.exit('unknown trader id type in market_session')\n\n        if best_buyer_id is not None:\n            line_str += 'best_B_id=,%s, best_B_prof=,%f, best_B_strat=, ' % (best_buyer_id, best_buyer_prof)\n            line_str += traders[best_buyer_id].strat_csv_str(best_buyer_strat)\n\n        if best_seller_id is not None:\n            line_str += 'best_S_id=,%s, best_S_prof=,%f, best_S_strat=, ' % (best_seller_id, best_seller_prof)\n            line_str += traders[best_seller_id].strat_csv_str(best_seller_strat)\n\n        line_str += '\\n'\n\n        if verbose:\n            print('line_str: %s' % line_str)\n        stratfile.write(line_str)\n        stratfile.flush()\n        os.fsync(stratfile)\n\n    def blotter_dump(session_id, trdrs):\n        \"\"\"\n        Write the blotter for each trader.\n        :param session_id: this market session's ID string (used for the filename).\n        :param trdrs: the population of traders.\n        :return: <nothing>\n        \"\"\"\n        bdump = open(session_id+'_blotters.csv', 'w')\n        for trdr in trdrs:\n            bdump.write('%s, %d\\n' % (trdrs[trdr].tid, len(trdrs[trdr].blotter)))\n            for b in trdrs[trdr].blotter:\n                bdump.write('%s, %s, %.3f, %d, %s, %s, %d\\n'\n                            % (traders[trdr].tid, b['type'], b['time'], b['price'], b['party1'], b['party2'], b['qty']))\n        bdump.close()\n\n    orders_verbose = False\n    lob_verbose = False\n    process_verbose = False\n    respond_verbose = False\n    bookkeep_verbose = False\n    populate_verbose = False\n\n    if dumpfile_flags['dump_strats']:\n        strat_dump = open(sess_id + '_strats.csv', 'w')\n    else:\n        strat_dump = None\n\n    if dumpfile_flags['dump_lobs']:\n        lobframes = open(sess_id + '_LOB_frames.csv', 'w')\n    else:\n        lobframes = None\n\n    if dumpfile_flags['dump_avgbals']:\n        avg_bals = open(sess_id + '_avg_balance.csv', 'w')\n    else:\n        avg_bals = None\n        \n    if dumpfile_flags['dump_tape']:\n        # NB writing transactions only -- not writing cancellations\n        tape_dump = open(sess_id + '_tape.csv', 'w')\n    else:\n        tape_dump = None\n        \n    # initialise the exchange\n    exchange = Exchange()\n\n    # create a bunch of traders\n    traders = {}\n    trader_stats = populate_market(trader_spec, traders, True, populate_verbose)\n\n    # timestep set so that can process all traders in one second\n    # NB minimum interarrival time of customer orders may be much less than this!!\n    timestep = 1.0 / float(trader_stats['n_buyers'] + trader_stats['n_sellers'] + trader_stats['n_proptraders'])\n\n    session_duration = float(endtime - starttime)\n\n    time = starttime\n\n    pending_cust_orders = []\n\n    if sess_vrbs:\n        print('\\n%s;  ' % sess_id)\n\n    # frames_done is record of what frames we have printed data for thus far\n    frames_done = set()\n\n    while time < endtime:\n\n        # how much time left, as a percentage?\n        time_left = (endtime - time) / session_duration\n\n        if sess_vrbs:\n            print('\\n\\n%s; t=%08.2f (%4.1f/100) ' % (sess_id, time, time_left*100))\n\n        [pending_cust_orders, kills] = customer_orders(time, traders, trader_stats,\n                                                       order_schedule, pending_cust_orders, orders_verbose)\n\n        # if any newly-issued customer orders mean quotes on the LOB need to be cancelled, kill them\n        if len(kills) > 0:\n            # if verbose : print('Kills: %s' % (kills))\n            for kill in kills:\n                # if verbose : print('lastquote=%s' % traders[kill].lastquote)\n                if traders[kill].lastquote is not None:\n                    # if verbose : print('Killing order %s' % (str(traders[kill].lastquote)))\n                    # NB if exchange.del_order() third argument = None then cancellations not written to tape file.\n                    # exchange.del_order(time, traders[kill].lastquote, tape_dump, sess_vrbs)\n                    exchange.del_order(time, traders[kill].lastquote, None, sess_vrbs)\n\n        # get a limit-order quote (or None) from a randomly chosen trader\n        tid = list(traders.keys())[random.randint(0, len(traders) - 1)]\n\n        order = traders[tid].getorder(time, time_left, exchange.publish_lob(time, lobframes, lob_verbose))\n        if sess_vrbs:\n            print('trader=%s order=%s' % (tid, order))\n\n        if order is not None:\n            if order.otype == 'Ask' and order.price < traders[tid].orders[0].price:\n                sys.exit('Bad ask')\n            if order.otype == 'Bid' and order.price > traders[tid].orders[0].price:\n                sys.exit('Bad bid')\n            # send order to exchange\n            traders[tid].n_quotes = 1\n            trade = exchange.process_order(time, order, tape_dump, process_verbose)\n            if trade is not None:\n                # trade occurred,\n                # so the counterparties update order lists and blotters\n                traders[trade['party1']].bookkeep(time, trade, order, bookkeep_verbose)\n                traders[trade['party2']].bookkeep(time, trade, order, bookkeep_verbose)\n                if dumpfile_flags['dump_avgbals']:\n                    trade_stats(sess_id, traders, avg_bals, time, exchange.publish_lob(time, lobframes, lob_verbose))\n\n            # traders respond to whatever happened\n            lob = exchange.publish_lob(time, lobframes, lob_verbose)\n            any_record_frame = False\n            for t in traders:\n                # NB respond just updates trader's internal variables\n                # doesn't alter the LOB, so processing each trader in\n                # sequence (rather than random/shuffle) isn't a problem\n                record_frame = traders[t].respond(time, lob, trade, respond_verbose)\n                if record_frame:\n                    any_record_frame = True\n\n            # log all the PRSH/PRDE/ZIPSH strategy info for this timestep?\n            if any_record_frame and dumpfile_flags['dump_strats']:\n                # print one more frame to strategy dumpfile\n                dump_strats_frame(time, strat_dump, traders)\n                # record that we've written this frame\n                frames_done.add(int(time))\n\n        time = time + timestep\n\n    # session has ended\n\n    # write trade_stats for this session (NB could use this to write end-of-session summary only)\n    if dumpfile_flags['dump_avgbals']:\n        trade_stats(sess_id, traders, avg_bals, time, exchange.publish_lob(time, lobframes, lob_verbose))\n        avg_bals.close()\n\n    if dumpfile_flags['dump_blotters']:\n        # record the blotter for each trader\n        blotter_dump(sess_id, traders)\n\n    if dumpfile_flags['dump_strats']:\n        strat_dump.close()\n\n    if dumpfile_flags['dump_lobs']:\n        lobframes.close()\n\n\n#############################\n# # Below here is where we set up and run a whole series of experiments\n\nif __name__ == \"__main__\":\n\n    price_offset_filename = 'offset_BTC_USD_20250211.csv'\n\n    # if called from the command line with one argument, the first argument is the price offset filename\n    if len(sys.argv) > 1:\n        price_offset_filename = sys.argv[1]\n\n    # set up common parameters for all market sessions\n    # 1000 days is often good, but 3*365=1095, so may as well go for three years.\n    n_days = 1\n    hours_in_a_day = 24     # how many hours the exchange operates for in a working day (e.g. NYSE = 7.5)\n    start_time = 0.0\n    end_time = 60.0 * 60.0 * hours_in_a_day * n_days\n    duration = end_time - start_time\n\n\n    def schedule_offsetfn_read_file(filename, col_t, col_p, scale_factor=75):\n        \"\"\"\n        Read in a CSV data-file for the supply/demand schedule time-varying price-offset value\n        :param filename: the CSV file to read\n        :param col_t: column in the CSV that has the time data\n        :param col_p: column in the CSV that has the price data\n        :param scale_factor: multiplier on prices\n        :return: on offset value event-list: one item for each change in offset value\n                -- each item is percentage time elapsed, followed by the new offset value at that time\n        \"\"\"\n        \n        vrbs = True\n        \n        # does two passes through the file\n        # assumes data file is all for one date, sorted in time order, in correct format, etc. etc.\n        rwd_csv = csv.reader(open(filename, 'r'))\n        \n        # first pass: get time & price events, find out how long session is, get min & max price\n        minprice = None\n        maxprice = None\n        firsttimeobj = None\n        timesincestart = 0\n        priceevents = []\n        \n        first_row_is_header = True\n        this_is_first_row = True\n        this_is_first_data_row = True\n        first_date = None\n        \n        for line in rwd_csv:\n            \n            if vrbs:\n                print(line)\n            \n            if this_is_first_row and first_row_is_header:\n                this_is_first_row = False\n                this_is_first_data_row = True\n                continue\n                \n            row_date = line[col_t][:10]\n            \n            if this_is_first_data_row:\n                first_date = row_date\n                this_is_first_data_row = False\n                \n            if row_date != first_date:\n                continue\n                \n            time = line[col_t][11:19]\n            if firsttimeobj is None:\n                firsttimeobj = datetime.strptime(time, '%H:%M:%S')\n                \n            timeobj = datetime.strptime(time, '%H:%M:%S')\n            \n            price_str = line[col_p]\n            # delete any commas so 1,000,000 becomes 1000000\n            price_str_no_commas = price_str.replace(',', '')\n            price = float(price_str_no_commas)\n            \n            if minprice is None or price < minprice:\n                minprice = price\n            if maxprice is None or price > maxprice:\n                maxprice = price\n            timesincestart = (timeobj - firsttimeobj).total_seconds()\n            priceevents.append([timesincestart, price])\n            \n            if vrbs:\n                print(row_date, time, timesincestart, price)\n            \n        # second pass: normalise times to fractions of entire time-series duration\n        #              & normalise price range\n        pricerange = maxprice - minprice\n        endtime = float(timesincestart)\n        offsetfn_eventlist = []\n        for event in priceevents:\n            # normalise price\n            normld_price = (event[1] - minprice) / pricerange\n            # clip\n            normld_price = min(normld_price, 1.0)\n            normld_price = max(0.0, normld_price)\n            # scale & convert to integer cents\n            price = int(round(normld_price * scale_factor))\n            normld_event = [event[0] / endtime, price]\n            if vrbs:\n                print(normld_event)\n            offsetfn_eventlist.append(normld_event)\n        \n        return offsetfn_eventlist\n\n\n    def schedule_offsetfn_from_eventlist(time, params):\n        \"\"\"\n        Returns a price offset-value for the current time, by reading from an offset event-list.\n        :param time: the current time\n        :param params: a list of parameter values...\n            params[1] is the final time (the end-time) of the current session.\n            params[2] is the offset event-list: one item for each change in offset value\n                        -- each item is percentage time elapsed, followed by the new offset value at that time\n        :return: integer price offset value\n        \"\"\"\n\n        final_time = float(params[0])\n        offset_events = params[1]\n        # this is quite inefficient: on every call it walks the event-list\n        percent_elapsed = time/final_time\n        offset = None\n        for event in offset_events:\n            offset = event[1]\n            if percent_elapsed < event[0]:\n                break\n        return offset\n\n\n    def schedule_offsetfn_increasing_sinusoid(t, params):\n        \"\"\"\n        Returns sinusoidal time-dependent price-offset, steadily increasing in frequency & amplitude\n        :param t: time\n        :param params: set of parameters for the offsetfn: this is empty-set for this offsetfn but nonempty in others\n        :return: the time-dependent price offset at time t\n        \"\"\"\n        if params is None:  # this test of params is here only to prevent PyCharm from warning about unused parameters\n            pass\n        scale = -7500\n        multiplier = 7500000    # determines rate of increase of frequency and amplitude\n        offset = ((scale * t) / multiplier) * (1 + math.sin((t*t)/(multiplier * math.pi)))\n        return int(round(offset, 0))\n\n    # Here is an example of how to use the offset function\n    #\n    # range1 = (10, 190, (schedule_offsetfn, args)) # args is the list of arguments to the function\n    # range2 = (200, 300, (schedule_offsetfn, args))\n\n    # Here is an example of how to switch from range1 to range2 and then back to range1,\n    # introducing two \"market shocks\"\n    # -- here the timings of the shocks are at 1/3 and 2/3 into the duration of the session.\n    #\n    # supply_schedule = [ {'from':start_time, 'to':duration/3, 'ranges':[range1], 'stepmode':'fixed'},\n    #                     {'from':duration/3, 'to':2*duration/3, 'ranges':[range2], 'stepmode':'fixed'},\n    #                     {'from':2*duration/3, 'to':end_time, 'ranges':[range1], 'stepmode':'fixed'}\n    #                   ]\n\n    offsetfn_events = None\n    if price_offset_filename is not None:\n        offsetfn_events = schedule_offsetfn_read_file(price_offset_filename, 0, 1)\n\n    # supply schedule (defines the supply curve)\n    range1 = (75, 110, (schedule_offsetfn_from_eventlist, [[end_time, offsetfn_events]]))\n    supply_schedule = [{'from': start_time, 'to': end_time, 'ranges': [range1], 'stepmode': 'random'}]\n\n    # demand schedule (defines the demand curve)\n    range2 = (125, 90, (schedule_offsetfn_from_eventlist, [[end_time, offsetfn_events]]))\n    demand_schedule = [{'from': start_time, 'to': end_time, 'ranges': [range2], 'stepmode': 'random'}]\n\n    # new customer orders arrive at each trader approx once every order_interval seconds\n    order_interval = 10\n\n    # order schedule wraps up the supply/demand schedules and details of how customer orders/assignments are issued\n    order_sched = {'sup': supply_schedule, 'dem': demand_schedule,\n                   'interval': order_interval, 'timemode': 'drip-poisson'}\n\n    # now run a sequence of trials, one session per trial\n\n    # if verbose = True, print a running commentary describing what's going on.\n    verbose = False\n\n    # n_trials is how many trials (i.e. market sessions) to run in total\n    n_trials = 1\n\n    # n_recorded is how many trials (i.e. market sessions) to write full data-files for\n    n_trials_recorded = 5\n\n    trial = 1\n\n    while trial < (n_trials+1):\n\n        # create unique i.d. string for this trial\n        trial_id = 'bse_d%03d_i%02d_%04d' % (n_days, order_interval, trial)\n\n        # buyer_spec specifies the strategies played by buyers, and for each strategy how many such buyers to create\n        buyers_spec = [('SHVR', 5), ('GVWY', 5), ('ZIC', 2), ('ZIP', 13)]\n        #     ('PRZI', 5, {'s_min': -1.0, 's_max': +1.0})]\n\n        # seller_spec specifies the strategies played by sellers, and for each strategy how many such sellers to create\n        sellers_spec = buyers_spec\n\n        # proptraders_spec specifies strategies played by proprietary-traders, and how many of each\n        proptraders_spec = [('PT1', 1, {'bid_percent': 0.95, 'ask_delta': 7}), ('PT2', 1, {'n_past_trades': 25})]\n\n        # trader_spec wraps up the specifications for the buyers, sellers, and proptraders\n        traders_spec = {'sellers': sellers_spec, 'buyers': buyers_spec, 'proptraders': proptraders_spec}\n\n        if trial > n_trials_recorded:\n            # switch off recording of detailed data-files\n            dump_flags = {'dump_blotters': False, 'dump_lobs': False, 'dump_strats': False,\n                          'dump_avgbals': False, 'dump_tape': False}\n        else:\n            # we're still recording all the required data-files\n            dump_flags = {'dump_blotters': True, 'dump_lobs': False, 'dump_strats': True,\n                          'dump_avgbals': True, 'dump_tape': True}\n\n        # simulate the market session\n        market_session(trial_id, start_time, end_time, traders_spec, order_sched, dump_flags, verbose)\n\n        trial = trial + 1\n\n    # The code in comments below here is for illustration, in case you want to do an exhaustive sweep of all possible\n    # combinations of some set of trading strategies: if its of no interest, it can be deleted.\n    #\n    # run a sequence of trials that exhaustively varies the ratio of four trader types\n    # NB this has weakness of symmetric proportions on buyers/sellers -- combinatorics of varying that are quite nasty\n    #\n    # n_trader_types = 4\n    # equal_ratio_n = 4\n    # n_trials_per_ratio = 50\n    #\n    # n_traders = n_trader_types * equal_ratio_n\n    #\n    # fname = 'balances_%03d.csv' % equal_ratio_n\n    #\n    # tdump = open(fname, 'w')\n    #\n    # min_n = 1\n    #\n    # trialnumber = 1\n    # trdr_1_n = min_n\n    # while trdr_1_n <= n_traders:\n    #     trdr_2_n = min_n\n    #     while trdr_2_n <= n_traders - trdr_1_n:\n    #         trdr_3_n = min_n\n    #         while trdr_3_n <= n_traders - (trdr_1_n + trdr_2_n):\n    #             trdr_4_n = n_traders - (trdr_1_n + trdr_2_n + trdr_3_n)\n    #             if trdr_4_n >= min_n:\n    #                 buyers_spec = [('GVWY', trdr_1_n), ('SHVR', trdr_2_n),\n    #                                ('ZIC', trdr_3_n), ('ZIP', trdr_4_n)]\n    #                 sellers_spec = buyers_spec\n    #                 traders_spec = {'sellers': sellers_spec, 'buyers': buyers_spec}\n    #                 # print buyers_spec\n    #                 trial = 1\n    #                 while trial <= n_trials_per_ratio:\n    #                     trial_id = 'trial%07d' % trialnumber\n    #                     market_session(trial_id, start_time, end_time, traders_spec,\n    #                                    order_sched, tdump, False, True)\n    #                     tdump.flush()\n    #                     trial = trial + 1\n    #                     trialnumber = trialnumber + 1\n    #             trdr_3_n += 1\n    #         trdr_2_n += 1\n    #     trdr_1_n += 1\n    # tdump.close()\n    #\n    # print(trialnumber)\n"
  },
  {
    "path": "BSE_VernonSmith1962_demo.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    },\n    \"tags\": []\n   },\n   \"source\": [\n    \"# Simple BSE demo/walkthrough\\n\",\n    \"Dave Cliff, University of Bristol, October 2022\\n\",\n    \"\\n\",\n    \"\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"## BSE System Architecture\\n\",\n    \"\\n\",\n    \"The figure below shows a schematic illustration of the overall architecture of the *Bristol Stock Exchange* (BSE), a simulation of a contemporary fully electronic financial exchange with automated traders.\"\n   ]\n  },\n  {\n   \"attachments\": {\n    \"8626ec3c-5c9c-4ae1-821a-31ee98123508.png\": {\n     \"image/png\": \"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\\nHm+Ton0A7OioGFP98ETvPm5Y5Cum2FxTA73+RrMwD/zDJvv67/b9zxkoVP82/wtGFg4dGvBaHgAA\\nAFZlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA5KGAAcAAAASAAAARKACAAQAAAABAAAC\\nnKADAAQAAAABAAACgAAAAABBU0NJSQAAAFNjcmVlbnNob3RF2l2VAAAB1mlUWHRYTUw6Y29tLmFk\\nb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0i\\nWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3Jn\\nLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjph\\nYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYv\\nMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj42NDA8L2V4aWY6UGl4ZWxZRGlt\\nZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+NjY4PC9leGlmOlBpeGVsWERp\\nbWVuc2lvbj4KICAgICAgICAgPGV4aWY6VXNlckNvbW1lbnQ+U2NyZWVuc2hvdDwvZXhpZjpVc2Vy\\nQ29tbWVudD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1l\\ndGE+CsCaQrwAAEAASURBVHgB7L0HYF7VfTb+vEOvtiwP2fK2sQ02YDYESCgQQiAkbSgZbVZJ06Rp\\nku6m/bf9Jx3p/NKvX/q1SdOZNINmkCZpRgkQEkLY4IABgwfe25Zkbend3/P8zr3SKyFbNshGkn9H\\neu8994zfOee555773N9ZiTIN3DgCjoAj4Ag4Ao6AI+AIOAInCYHkSZLrYh0BR8ARcAQcAUfAEXAE\\nHAFDwAmnVwRHwBFwBBwBR8ARcAQcgZOKgBPOkwqvC3cEHAFHwBFwBBwBR8ARcMLpdcARcAQcAUfA\\nEXAEHAFH4KQi4ITzpMLrwh0BR8ARcAQcAUfAEXAEnHB6HXAEHAFHwBFwBBwBR8AROKkIOOE8qfC6\\n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\\nP8affOZj8cq774nX3P22GGXj0T/5578ef+kv/HLcedO9MbqOTUgkv8zayYmx9fHX/9Lfin/1H/5Z\\nDHBL01/9+b8ZE6T1vcfvB/az8Wd/7hfRQr49pg/OxrrhsVwrKeYlRGDjX6Ehf0xX34Im8B1vfmN8\\n8rMfjX/8T3813nTfO+Mdb/kpNifdGD/2oz/F+svF+ONPfij+xl/59dh+zR0IndwRhDB9YHJPvPut\\nfyZ+6l3vj9HhEZYW7I2/97f+YWy79mUxvzyNQP0v4oEHvhE/+sb3I/j9WdYJHoyvfvXz8Wt/8x/F\\nlrHtbDRajA/9lw/EuomNmZ8t6zfFl/7bp4j3/8X3Hv16bNq0Ib72lS/ET77zp+Mn3v4z8dTTP4i/\\n/7//erztze9mKv021m9+g1wgSA8MxQt7n4sPf/x34040un/+534ZzeVA/N4f/Mv44uc/Gfe+4o3x\\n9FPfj9nDu+Iv/vlfijtvf0PMTC/G2PAE8Z32r2OLXrSweV5UvW6ebu3tuxA88utESJ96yBNB6fld\\nGhRoucU2pmd6FHgpKdATOF9KavfSeokp4Bq35udYHmtpb2fjDz/ygfjEyEdj/4HnY/3EhvjZ9/wc\\nAqdXA9ZquB/7kffG9qvvZDpzIe7/1lcRUA/Ej+N2GVPEg9x49LpXvjW+9JVPxzPPPBH3vfLt7HQv\\nYWjd8IZYv24T+ZxHYJxnzaO3KAUC3gRC30hq8ibGtsa6ofHYQLghNJV/8ulPxKb1V8XN192CcDrB\\ncj7X8YGvWl+m0GtiXV0E1ZVbg4aY5n//e/9S3HrzXQhtH4xPfPaP436m7P/Or/zDuPqKm2JkeBNC\\n2VisY8PQ/8/eewdbmlyHff3uvS/HyXFnZnc2YneRQYBBJE3QIljMtEklV9FJtuXAYukPy7QlS+WS\\nSi5ZrpJs+Q/RlFSkTYoyKYoQAyAQBEEQILAIi7RYbA6T45uZl8O97/n3O/31vfe9eROwmJnd2b09\\n8+73fR1Pnz59+vTp091jg0MsuWNzyQadicmd6UN//qfS7u33ejZ+2n94J0vgl9L0hZPpkjv3KWKB\\n247S+hI2ptvSKOkbbAoaH55kyXyMjVGn04svPJ32Hj6Qnn31GerTQIN5KbS2p06/nCYnHkzLK/Mh\\nVNcHh9OO3fuoBXfncGwPa/FhnqDZQatvMZ0+f5wl83Pp0JHD6amnn+SA8mzyMDs/l6anZ9PE1K6w\\n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\\n\"\n    }\n   },\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"![BSE_system_diagram.png](attachment:8626ec3c-5c9c-4ae1-821a-31ee98123508.png)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"BSE simulates a *market*, composed of an *exchange* and some number *N* of *traders* which each interact with the exchange. Any one simulation of a market session proceeds according to BSE's *system clock*, which provides a unified time signal to all elements of the simulation.\\n\",\n    \"\\n\",\n    \"Separate from the simulation of the market is BSE's *session control* logic, which determines the (potentially time-dependent) market's *supply and demand schedule* (SDS): this is used to issue *assignments* to the traders, i.e. allocations of cash and limit-prices to buyers, and allocations of stock and limit-prices to sellers -- this is the simulation's correlate of real-world market *customer orders* coming from customers to sales-traders who are responsible for working each customer order. The session-control logic is also responsible for recording whole-market data, such as the profits and strategy-values of each trader in the market, as were visualised in the graphs and plots earlier in this paper.\\n\",\n    \"\\n\",\n    \"The exchange receives orders from the traders: *bids* from buyers; *asks* from sellers. When each order arrives at the exchange, it is processed by the *matching engine*, attempting to find one or more matching bids for a newly-arrived ask, or one or more matching asks for a newly-arrived bid. It does this by comparing the new order to those earlier orders, as yet unfulfilled, that are \\\"resting\\\" at the exchange and which are summarised in aggregated and anonymized form on the exchange's *limit order book* (LOB). If a new order can be matched with one or more existing orders on the LOB then the matching orders are removed from the LOB, and the new order plus its counterparty orders from the LOB are recorded as fulfilled, resulting in a transaction taking place. When a transaction occurs, its details are written to the exchange's public record of transactions which is commonly referred to as the exchange's *tape* -- the tape records transactions and also other notable market events, such as cancellations of existing orders. When a transaction occurs, the exchange also notifies the traders concerned, adjusting their cash balances appropriately. The BSE exchange also can be configured to write the state of the LOB at any one instance (referred to as a *LOB frame*) to an external record, the *LOB framestore*, for subsequent analysis.\\n\",\n    \"\\n\",\n    \"Each of the *N* traders in the market receives occasional fresh assignments from the session control, all have the same view of the LOB data published by the exchange, and when a trader is involved in a transaction it receives notification of the relevant details from the exchange's matching engine. Each trader is able to send orders to the exchange, and to send cancellations of existing orders, and each maintains its own local private record of assignments received, orders sent to the exchange, and transaction details received from the exchange: this is conventionally referred to as the trader's *blotter*.\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"## Using BSE: a first walk-through\\n\",\n    \"\\n\",\n    \"Let's start by using BSE to replicate the experiment that Vernon Smith showed results from in Chart 1 of his landmark 1962 JPE paper *\\\"An Experimental Study of Competitive Market Behavior\\\"* -- this was Smith's first reported CDA experiment.\\n\",\n    \"\\n\",\n    \"For a PDF version of Smith's 1962 paper, see here: https://www.journals.uchicago.edu/doi/abs/10.1086/258609\\n\",\n    \"\\n\",\n    \"First of all let's import what we'll need.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"is_executing\": true,\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"# un-comment these lines if you need to install the packages\\n\",\n    \"# !{sys.executable} pip3 install numpy\\n\",\n    \"# !{sys.executable} pip3 install matplotlib\\n\",\n    \"\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"import numpy as np\\n\",\n    \"import csv\\n\",\n    \"import random\\n\",\n    \"\\n\",\n    \"from BSE import market_session\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"Let's say all our experiments are to last for 10 simulated minutes...\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"start_time = 0\\n\",\n    \"end_time = 60 * 10\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"The supply and demand curves in Smith's Chart 1 are symmetric: they each involve 11 traders, each given an assignment to trade (buy or sell) a single unit.\\n\",\n    \"\\n\",\n    \"On both curves the minimum price was 80 and the max was 320,\\n\",\n    \"and the step-size between successive prices was always 20\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"chart1_range=(80, 320)\\n\",\n    \"\\n\",\n    \"supply_schedule = [{'from': start_time, 'to': end_time, 'ranges': [chart1_range], 'stepmode': 'fixed'}]\\n\",\n    \"demand_schedule = [{'from': start_time, 'to': end_time, 'ranges': [chart1_range], 'stepmode': 'fixed'}]\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"Smith used periodic updating -- at the start of each \\\"day\\\" all traders are issued with fresh assignments.\\n\",\n    \"\\n\",\n    \"Let's do that once every 60 seconds\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 4,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"order_interval = 60\\n\",\n    \"order_sched = {'sup': supply_schedule, 'dem': demand_schedule,\\n\",\n    \"               'interval': order_interval, 'timemode': 'periodic'}\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"And finally let's use 11 ZIP traders on each side, buyers and sellers, because ZIP gives reasonably human-like market dynamics.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 5,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"sellers_spec = [('ZIP', 11)]\\n\",\n    \"buyers_spec = sellers_spec\\n\",\n    \"prop_traders_spec = []\\n\",\n    \"traders_spec = {'sellers': sellers_spec, 'buyers': buyers_spec, 'proptraders': prop_traders_spec}\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"When we run a BSE market session we can alter how verbose it is, how much it tells us about what is going on, but this can generate a *lot* of text, so let's switch that off for the time being.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 6,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"verbose = False\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"Finally BSE (which was originally created before the days of Jupyter notebooks) writes output data-files\\n\",\n    \"in csv format for later anaylsis, so we need to give it a session-identifier string which will be used at the start of all this session's data-files, and what data to dump into files.\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 7,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"\\n\",\n    \"trial_id = 'smith_chart_1'\\n\",\n    \"dump_flags = {'dump_blotters': True, 'dump_lobs': True, 'dump_strats': True,\\n\",\n    \"              'dump_avgbals': True, 'dump_tape': True}\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"And now we're ready to go... we'll run a market session, which dumps data to a file, and then we'll immediately read the file back and plot a graph of the transaction-price time-series.\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 8,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"random.seed(100) # changing the seed value will give us different seqences of random numbers\\n\",\n    \"\\n\",\n    \"market_session(trial_id, start_time, end_time, traders_spec, order_sched, dump_flags, verbose)\\n\",\n    \"\\n\",\n    \"prices_fname = trial_id + '_tape.csv'\\n\",\n    \"x = np.empty(0)\\n\",\n    \"y = np.empty(0)\\n\",\n    \"with open(prices_fname, newline='') as csvfile:\\n\",\n    \"    reader = csv.reader(csvfile)\\n\",\n    \"    for row in reader:\\n\",\n    \"        time = float(row[1])\\n\",\n    \"        price = float(row[2])\\n\",\n    \"        x = np.append(x,time)\\n\",\n    \"        y = np.append(y,price)\\n\",\n    \"\\n\",\n    \"plt.plot(x, y, 'x', color='black');\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"But that's just one run from a stochastic system: if we run it again with a different random seed we'll get a different sequence of events.\\n\",\n    \"\\n\",\n    \"Note that while ZIP is pretty good at doing what it does, there are a couple of known issues when a market is populated entirely by ZIP traders (i.e., when it is a homogeneous population of ZIPs): (a) sometimes a homogenous ZIP market will fail to equilibrate at all, or maybe it will converge to a steady-state range of transaction prices that is clearly off-equilibrium; or (b) sometimes a homogeneous ZIP market will grind to a halt, with a total cessation of trading.\\n\",\n    \"\\n\",\n    \"The behavior of each ZIP trader is determined by eight numeric parameters such as its\\n\",\n    \"learning rate, its momentum parameter, and the two constants used for relative and absolute perturbation of the target price -- these parameters can be fine-tuned to particular market scenarios, and if the parameters are not tuned to the market situation, sometimes problem (a) occurs.\\n\",\n    \"\\n\",\n    \"Also ZIP, as implemented here, was originally intended for operating in simulation models of open-outcry trading pits, where there is a lot of (noisy) information to act upon. In a Limit Order Book (LOB) trading scenario, ZIP does not always do so well and sometimes a homogeneous population of ZIPs \\\"locks up\\\", causing problem (b), because every ZIP in the market is waiting for some other ZIP to issue a quote that changes the LOB, and because they are all waiting, nobody does anything. This problem disappears once there are one or more other traders present, even if they're just noise traders like Gode & Sunder's ZI-U or ZI-C, because the other traders put enough life into the LOB to prevent the ZIPs from locking up.\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"Analysis of individual runs is important, but it's also important to characterise the general behavior of the system -- for example, we could do 10 or 50 or 100 (or more) independent and identically distributed (iid) runs, and compute summary statistics. In the original ZIP paper (HP Labs Technical Report, 1997) multiple transaction-price time series were summarised by showing the mean price plus and minus one standard deviation. That's a very straightforward way of doing things.\\n\",\n    \"\\n\",\n    \"Let's take the code in the previous cell and wrap a loop around it, so that instead of doing a single session, it does n_sessions.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 9,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"n_sessions = 10\\n\",\n    \"\\n\",\n    \"x = np.empty(0)\\n\",\n    \"y = np.empty(0)\\n\",\n    \"\\n\",\n    \"for sess in range(n_sessions):\\n\",\n    \"    trial_id = 'smith_chart_' + str(sess)\\n\",\n    \"\\n\",\n    \"    market_session(trial_id, start_time, end_time, traders_spec, order_sched, dump_flags, verbose)\\n\",\n    \"\\n\",\n    \"    prices_fname = trial_id + '_tape.csv'\\n\",\n    \"    with open(prices_fname, newline='') as csvfile:\\n\",\n    \"        reader = csv.reader(csvfile)\\n\",\n    \"        for row in reader:\\n\",\n    \"            time = float(row[1])\\n\",\n    \"            price = float(row[2])\\n\",\n    \"            x = np.append(x,time)\\n\",\n    \"            y = np.append(y,price)\\n\",\n    \"\\n\",\n    \"plt.plot(x, y, 'x', color='black');\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"As you can see, ZIP is not perfect (ZIP was originally written to operate in a market\\n\",\n    \"that is a model of an open-outcry trading pit, rather than a LOB), but the results we're getting here from ZIP in BSE are illustrative of machine trading on an automated exchange: no-one is saying ZIP is optimal!\\n\",\n    \"\\n\",\n    \"To make things a bit more realistic, let's change the re-supply of buyer and seller assignments from periodic to stochastic, feeding them into the market via a Poisson process, and make the schedule re-supply be on a 10-second cycle...\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 10,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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10+9GFEEACiFfHJYaowxJtdgp6amRmvWrNHChQtd15900kk666yzdM8996Tdz+bNmzV9+nRt3rxZp556ar/1sVhMsVgs+by3t1cTJkxQT0+PRo4cmWvxPTkvn9ifOy+fzJo1S5K0YcMGdXV16emnn072sEgfzG47e/bs5PJCzF47a9Ysbdy4UVJqDovzfZ2sHhXrNYUqDwAAmfT29qquri639jufSElpelieeuopI8ls3bo14376+vrMkCFDzKpVq3y9b7lnurVz66Vwzm5b6J4Mt9lzvWbUdcP9igAA5VDSUUJ+Pfjgg5o2bZqmTJmScduXXnpJR44cUWNjY7GKUxRWD0a6UT+33XZbMhfGKxnWa7RQNBp17SXp7u5Ovq+1Tysnxr7ea5/OxGEAAIIu64Dl0KFD2rp1q7Zu3SpJ2rlzp7Zu3apdu3Ylt+nt7dVPf/pTffnLX+73+tdee02RSES//e1v9frrr+vxxx/X5z//eU2dOlVnnHFG7jUpAyuRVfogaKmtrU0uC4VCaYdA2/eRTTJsS0uL583kIpGIWlpaXN/LmUic7/BqAABKJtsumQ0bNrgmwC5evDi5zfe//30zdOhQc+DAgX6v37Vrl5k5c6apr6834XDYfOQjHzHXXHONeeutt3yXIaiXhOyTt/mdZM65D7fnhS6nn+UAABQaU/OXmduInWwDkELOhOuGmyUCAMotn/Y764njkF4oFOo3t4qfieLa29t12223ZbyElKt0k8IxSggAEHQELHmy8kKkD4YXt7W1qbW1Nbk8kUgoFAq5ThRnDZO257u4zaILAMBAVtSZbgcC+4gdK5HVvswKRqzgxd7TYQU7Tz/9NMmwAACkU4RLVEUXlByWbBJZ/c6em2nfAABUKnJYyiSRSHgOL7bWO5d1dHQkc1WsHpjW1lZf+wAAYKDKa2r+cslrat8yq62tVTweVygU0tGjR/utd7tzMndaBgBUg3zab3JYisRtBltrltmamholEgnNnj2733q3yeK40zIAYMAr+AWqEghKDks6mXJWmpubU+7snClnhTstAwAqHRPHFUEhJlpzBinOBFvreSgU8hV8FHtyOQAAiomApQgKNZW9tb1XUGIt93vnZO60DACoVIG8W3Ols24kaM8dsd880O+kbu3t7QqHw0okEv1msLUSZv3eOZk7LQMABqwiBFBFV8oclnwv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\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"order_interval = 10\\n\",\n    \"order_sched = {'sup': supply_schedule, 'dem': demand_schedule,\\n\",\n    \"               'interval': order_interval, 'timemode': 'drip-poisson'}\\n\",\n    \"\\n\",\n    \"n_sessions = 10\\n\",\n    \"\\n\",\n    \"x = np.empty(0)\\n\",\n    \"y = np.empty(0)\\n\",\n    \"\\n\",\n    \"for sess in range(n_sessions):\\n\",\n    \"    trial_id = 'smith_chart_' + str(sess)\\n\",\n    \"\\n\",\n    \"    market_session(trial_id, start_time, end_time, traders_spec, order_sched, dump_flags, verbose)\\n\",\n    \"\\n\",\n    \"    prices_fname = trial_id + '_tape.csv'\\n\",\n    \"    with open(prices_fname, newline='') as csvfile:\\n\",\n    \"        reader = csv.reader(csvfile)\\n\",\n    \"        for row in reader:\\n\",\n    \"            time = float(row[1])\\n\",\n    \"            price = float(row[2])\\n\",\n    \"            x = np.append(x,time)\\n\",\n    \"            y = np.append(y,price)\\n\",\n    \"\\n\",\n    \"plt.plot(x, y, 'x', color='black');\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"And let's increase the number of traders from 11 on each side to\\n\",\n    \"something bigger, say 40...\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 11,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAAAigAAAGdCAYAAAA44ojeAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABUYklEQVR4nO3dfXQb1Zk/8K88tuSQJlJMmtgmjqWwlJ4lNISEUl6MZRlCQwO00OW12/DSbF+StDkJp7+mRbKQsiRlD7Q9ZduyuyRACRtOT4Gypcs2WJFxlnIOJEAT2NJAZBMgbnZpbCchkeLx/f0R7mVmNCNLtmTL8fdzjk6imdFopJE0j+997nNdQggBIiIiojJSMdYHQERERGTFAIWIiIjKDgMUIiIiKjsMUIiIiKjsMEAhIiKissMAhYiIiMoOAxQiIiIqOwxQiIiIqOxUjvUBDMfg4CDef/99TJkyBS6Xa6wPh4iIiPIghMChQ4dQX1+PiorcbSTjMkB5//330dDQMNaHQURERMOwb98+zJo1K+c24zJAmTJlCoATL3Dq1KljfDRERESUj/7+fjQ0NKjreC7jMkCR3TpTp05lgEJERDTO5JOewSRZIiIiKjsMUIiIiKjsMEAhIiKissMAhYiIiMoOAxQiIiIqOwxQiIiIqOwwQCEiIqKywwCFiIiIyg4DFCIiIio7DFAsotEo4vG47bp4PI5oNDq6B0RERDQBMUCx0DQNkUgkK0iJx+OIRCLQNG2MjoyIiGjiGJdz8ZRSOBwGAEQiEXVfBiexWEytJyIiotJxCSHEWB9Eofr7++H1etHX11eyyQJlUOJ2u5HJZBicEBERjVAh1++Cunh+/vOf4zOf+YyaRfiCCy7Af/7nf6r1QghEo1HU19dj0qRJCAaDeP311037SKfTWLlyJaZPn47JkyfjqquuwrvvvlvIYYyKcDisghO3283ghIiIaBQVFKDMmjULGzZswMsvv4yXX34ZoVAIV199tQpC7rnnHtx33324//778dJLL6G2thaXXXYZDh06pPaxatUqPPnkk9iyZQu2b9+Ow4cPY8mSJdB1vbivbITi8bgKTjKZjGPiLBEREZWAGKFp06aJf/u3fxODg4OitrZWbNiwQa07duyY8Hq94he/+IUQQoje3l5RVVUltmzZorZ57733REVFhXj22Wfzfs6+vj4BQPT19Y308G3FYjEBQMRiMdv7REREVLhCrt/DHsWj6zq2bNmCI0eO4IILLkAqlUJPTw8WLVqktvF4PGhubsYLL7wAANixYweOHz9u2qa+vh5z585V29hJp9Po7+833UrFLiE2HA4jFovZju4hIiKi4it4FM+uXbtwwQUX4NixY/jEJz6BJ598En/7t3+rAoyZM2eatp85cya6u7sBAD09PXC73Zg2bVrWNj09PY7PuX79etx1112FHuqw6LpumxAr75dbVxQREdHJqOAA5cwzz8Srr76K3t5e/PrXv8bSpUvR0dGh1rtcLtP2QoisZVZDbbN27VqsXr1a3e/v70dDQ0Ohh56XXIXYmChLREQ0Ogru4nG73fibv/kbLFy4EOvXr8e8efPwk5/8BLW1tQCQ1RJy4MAB1apSW1uLTCaDgwcPOm5jx+PxqJFD8kZEREQnrxFXkhVCIJ1OIxAIoLa2Flu3blXrMpkMOjo6cOGFFwIAFixYgKqqKtM2+/fvx+7du9U2RERERAV18Xz/+9/H4sWL0dDQgEOHDmHLli1IJpN49tln4XK5sGrVKtx9990444wzcMYZZ+Duu+/GKaecgptuugkA4PV6cfvtt2PNmjU49dRTUVNTgzvuuANnn302Lr300pK8QCIiIhp/CgpQ/vKXv+Dv//7vsX//fni9XnzmM5/Bs88+i8suuwwA8N3vfhdHjx7Ft771LRw8eBDnn38+fv/732PKlClqHz/60Y9QWVmJ6667DkePHkVrayseeughznFDRERECkvdG0SjUWiaZpsMG4/Hoes6ZzMmIiIappKVuj/ZcSZjIiKi8sDZjA04kzEREVF5YBePDc5kTEREVHyFXL8ZoDjweDxqssB0Ol2S5yAiIppImIMyQpzJmIiIaGwxQLEw5pyk02lOEkhERDQGmCRr4DSTMWBOnCUiIqLSYoBiwJmMiYiIygOTZImIiGhUMEmWiIiIxjUGKERERFR2GKAQERFR2WGAQkRERGWHAQoRERGVHQYoREREVHYYoBAREVHZYYBCREREZYcBChEREZUdBihERERUdhigEBERUdlhgEJERERlhwGKRTQaRTwet10Xj8cRjUZH94CIiIgmIAYoFpqmIRKJZAUp8XgckUgEmqaN0ZERERFNHJVjfQDlJhwOAwAikYi6L4OTWCym1hMREVHpuIQQYqwPolD9/f3wer3o6+vD1KlTS/IcMihxu93IZDIMToiIiEaokOs3A5QcPB4PMpkM3G430ul0yZ6HiIhoIijk+s0cFAfxeFwFJ5lMxjFxloiIiIqPAYoNY85JOp1GLBazTZwlIiKi0mCSrIVdQqxd4iwRERGVDgMUC13XbRNi5X1d18fisIiIiCYUJskSERHRqChZkuz69etx3nnnYcqUKZgxYwa++MUv4s033zRt43K5bG//9E//pLYJBoNZ62+44YZCDoWIiIhOYgUFKB0dHVi+fDlefPFFbN26FQMDA1i0aBGOHDmittm/f7/ptnHjRrhcLlx77bWmfS1btsy03QMPPFCcV0RERETjXkE5KM8++6zp/qZNmzBjxgzs2LEDl1xyCQCgtrbWtM1vfvMbtLS0YM6cOablp5xySta2RERERMAIhxn39fUBAGpqamzX/+Uvf8EzzzyD22+/PWvd5s2bMX36dJx11lm44447cOjQIcfnSafT6O/vN92IiIjo5DXsUTxCCKxevRoXX3wx5s6da7vNww8/jClTpuCaa64xLb/55psRCARQW1uL3bt3Y+3atXjttdewdetW2/2sX78ed91113APlYiIiMaZYY/iWb58OZ555hls374ds2bNst3m05/+NC677DL89Kc/zbmvHTt2YOHChdixYwfOPffcrPXpdNpUar6/vx8NDQ0cxUNERDSOFDKKZ1gtKCtXrsTTTz+N559/3jE46ezsxJtvvonHH398yP2de+65qKqqwp49e2wDFI/HA4/HM5xDJSIionGooABFCIGVK1fiySefRDKZRCAQcNz2wQcfxIIFCzBv3rwh9/v666/j+PHjqKurK+RwiIiI6CRVUICyfPlyPPbYY/jNb36DKVOmoKenBwDg9XoxadIktV1/fz9+9atf4d57783ax9tvv43NmzfjiiuuwPTp0/HGG29gzZo1mD9/Pi666KIRvhwiIiI6GRQ0iufnP/85+vr6EAwGUVdXp27WbpwtW7ZACIEbb7wxax9utxvt7e24/PLLceaZZ+Lb3/42Fi1ahOeeew6apo3s1RAREdFJgaXuiYiIaFSUrNQ9ERER0WhggEJERERlhwEKERERlR0GKHmIRqOIx+O26+LxOKLR6OgeEBER0UmOAUoeNE1DJBLJClLi8TgikQhHHxERERXZsOfimUjC4TAAIBKJqPsyOInFYmo9ERERFQeHGRdABiVutxuZTIbBCRERUQEKuX4zQCmQx+NBJpOB2+02TWBIREREubEOSonE43EVnGQyGcfEWSIiIhoZBih5MuacpNNpxGIx28RZIiIiGjkmyebBLiHWLnGWiIiIioMBSh50XbdNiJX3dV0fi8MiIiI6aTFJloiIiEYFk2RHiJVjiYiIxhYDFBuycmxLS4spUDFWjmWgQkREVDrMQbFhTIBNJpNquUyUtf6fiIiIios5KDnIFhPJGpxw5A4REVH+WEm2iGTlWAAscU9ERDQCTJItEmPlWADq/wxOiIiISosBigNjcbY777xTLWeJeyIiotJjgGLDGJwAH+ecGO8zSCEiIiodjuKxISvHAvYJsYlEgiXuiYiISohJsjlEo1FommYbhMTjcei6zlooREREeeIoHiIiIio7HMVDRERE4xoDFAecj4eIiGjsMEnWQUdHhypzb8xBkSN8gsHg2BwYERHRBMAWFAehUAiAeUixsfS9XE9ERETFxyTZHIwBiSxzD4Cl7omIiIaBSbJFEg6HVT0UBidERESjhwEKERERlZ2CApT169fjvPPOw5QpUzBjxgx88YtfxJtvvmna5pZbboHL5TLdPve5z5m2SafTWLlyJaZPn47JkyfjqquuwrvvvjvyV1Nk1i4egGXuiYiIRkNBAUpHRweWL1+OF198EVu3bsXAwAAWLVqEI0eOmLb7/Oc/j/3796vb7373O9P6VatW4cknn8SWLVuwfft2HD58GEuWLIGu6yN/RUViDE5isRjS6TTn4iEiIhotYgQOHDggAIiOjg61bOnSpeLqq692fExvb6+oqqoSW7ZsUcvee+89UVFRIZ599tm8nrevr08AEH19fcM+9qEEg0EBQMRiMdPyWCwmAIhgMFiy5yYiIjoZFXL9HlEdlL6+PgBATU2NaXkymcSMGTPg8/nQ3NyMf/zHf8SMGTMAADt27MDx48exaNEitX19fT3mzp2LF154AZdffnnW86TTaaTTaXW/v79/JIedl+bmZoRCoayEWHm/nFp7iIiITjbDHmYshMDVV1+NgwcPorOzUy1//PHH8YlPfAKNjY1IpVIIh8MYGBjAjh074PF48Nhjj+HWW281BRwAsGjRIgQCATzwwANZzxWNRnHXXXdlLedcPERERONHIcOMh92CsmLFCvzxj3/E9u3bTcuvv/569f+5c+di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EYvFEIlE4PF4GJwQERGNoYIDlCNHjmDevHm4//77s9Z9+OGH2LlzJ8LhMHbu3IknnngCf/7zn3HVVVdlbbts2TLs379f3R544IHhvYIiCofDcLvdyGQycLvdDE6IiIjGSMFdPIsXL8bixYtt13m9XmzdutW07Kc//Sk++9nP4p133sHs2bPV8lNOOQW1tbWFPn1JxeNxFZxkMhnE43EGKURERGOg5EmyfX19cLlc8Pl8puWbN2/G9OnTcdZZZ+GOO+7AoUOHHPeRTqfR399vuhWbMecknU6r7h6n0T1ERERUOiVNkj127Bi+973v4aabbsLUqVPV8ptvvhmBQAC1tbXYvXs31q5di9deey2r9UVav3497rrrrpIdp11CrF3iLBEREY2OkgUox48fxw033IDBwUH87Gc/M61btmyZ+v/cuXNxxhlnYOHChdi5cyfOPffcrH2tXbsWq1evVvf7+/vR0NBQtGPVdd02IVbe13W9aM9FREREQytJgHL8+HFcd911SKVSSCQSptYTO+eeey6qqqqwZ88e2wDF4/HA4/GU4lABIGchNracEBERjb6iBygyONmzZw+2bduGU089dcjHvP766zh+/Djq6uqKfThEREQ0DhUcoBw+fBhvvfWWup9KpfDqq6+ipqYG9fX1+PKXv4ydO3fit7/9LXRdR09PDwCgpqYGbrcbb7/9NjZv3owrrrgC06dPxxtvvIE1a9Zg/vz5uOiii4r3yoiIiGjccgkhRCEPSCaTaGlpyVq+dOlSRKNRBAIB28dt27YNwWAQ+/btw1e+8hXs3r0bhw8fRkNDA77whS+gra0NNTU1eR1Df38/vF4v+vr6huw+IiIiovJQyPW74AClHDBAISIiGn8KuX5zskAiIiIqOwxQPhKNRh2LssXj8ZwjfYiIiKi4GKB8RNM028qxsoibpmljdGREREQTT0kryY4ndpVj7SrMEhERUekxSdZCBiVywkAGJ0RERMXBUTzDEI1GoWkawuEwPB6PmtU4nU4jHo9D13XmoRAREY0AR/EMg8xBaW1tVcFJJpNBa2src1CIiIhGGVtQDFpbW5FIJBAKhdDe3p51n4iIiIaPLSjDEI/HVTCSSCTg8XhM952GIBMREVHxMUD5iK7riMViaG9vV907brcb7e3tiMVi0HV9rA+RiIhowuAw44/IBNh4PG7KQYnH4xzFQ0RENMrYgmJgrHuSTqcRi8Vsi7cRERFRabEF5SN2RdnsircRERFR6TFA+YjMQbEGIfI+c1CIiIhGD4cZExER0ajgMGMiIiIa1xigEBERUdlhgEJERERlhwGKQTQadRxSHI/HOVkgERHRKGGAYiAnDLQGKXIIMicMJCIiGh0cZmxgV/fErj4KERERlRaHGduQQYksd8/ghIiIaOQKuX4zQHHg8XjUnDzpdLokz0FERDSRsA7KCNlNGEhERESjhwGKBScMJCIiGntMksWJ4cVyhI5dQmwwGOSEgURERKOIOSj4uNUkGAwiFApB1/WsgAWAWq7rOmuiEBERFaiQ6zdbUGAeXhwKhVQ9FACm1hRj9w8RERGVDgOUjxiDFLfbnbWe9VCIiIhGD7t4LIzDi++8807WQyEiIioSDjMeJuvwYgDq/263m8EJERHRKCk4QHn++edx5ZVXor6+Hi6XC0899ZRpvRAC0WgU9fX1mDRpEoLBIF5//XXTNul0GitXrsT06dMxefJkXHXVVXj33XdH9EJGyml4MeuhEBERjb6CA5QjR45g3rx5uP/++23X33PPPbjvvvtw//3346WXXkJtbS0uu+wyHDp0SG2zatUqPPnkk9iyZQu2b9+Ow4cPY8mSJdB1ffivZASGyi+58847WQ+FiIhoFBWcJLt48WIsXrzYdp0QAj/+8Y/xgx/8ANdccw0A4OGHH8bMmTPx2GOP4etf/zr6+vrw4IMP4pe//CUuvfRSAMCjjz6KhoYGPPfcc7j88stH8HKGR9f1nKN1jMOKWQ+FiIio9Io6iieVSqGnpweLFi1SyzweD5qbm/HCCy/g61//Onbs2IHjx4+btqmvr8fcuXPxwgsvjEmAYq1pYg1YJHl/rFp6iIiIJoqiBig9PT0AgJkzZ5qWz5w5E93d3Wobt9uNadOmZW0jH2+VTqdNE/b19/cX87Cz5CrCxpYTIiKi0ivJKB6Xy2W6L4TIWmaVa5v169fD6/WqW0NDQ9GOlYiIiMpPUQOU2tpaAMhqCTlw4IBqVamtrUUmk8HBgwcdt7Fau3Yt+vr61G3fvn3FPGwiIiIqM0UNUAKBAGpra7F161a1LJPJoKOjAxdeeCEAYMGCBaiqqjJts3//fuzevVttY+XxeDB16lTTjYiIiE5eBeegHD58GG+99Za6n0ql8Oqrr6KmpgazZ8/GqlWrcPfdd+OMM87AGWecgbvvvhunnHIKbrrpJgCA1+vF7bffjjVr1uDUU09FTU0N7rjjDpx99tlqVA8RERFNbAUHKC+//DJaWlrU/dWrVwMAli5dioceegjf/e53cfToUXzrW9/CwYMHcf755+P3v/89pkyZoh7zox/9CJWVlbjuuutw9OhRtLa24qGHHlIzCBMREdHExrl4iIiIaFRwLh4iIiIa1xigEBERUdlhgEJERERlhwEKERERlZ2ilrofLTKvt9Ql74mIiKh45HU7n/E54zJAOXToEACw5D0REdE4dOjQIXi93pzbjMthxoODg3j//fcxZcqUIef4KUR/fz8aGhqwb98+Dl8eJ3jOxieet/GH52z8KcdzJoTAoUOHUF9fj4qK3Fkm47IFpaKiArNmzSrZ/llOf/zhORufeN7GH56z8afcztlQLScSk2SJiIio7DBAISIiorLDAMXA4/Ggra0NHo9nrA+F8sRzNj7xvI0/PGfjz3g/Z+MySZaIiIhObmxBISIiorLDAIWIiIjKDgMUIiIiKjsMUIiIiKjsMED5yM9+9jMEAgFUV1djwYIF6OzsHOtDIoNoNAqXy2W61dbWqvVCCESjUdTX12PSpEkIBoN4/fXXx/CIJ57nn38eV155Jerr6+FyufDUU0+Z1udzjtLpNFauXInp06dj8uTJuOqqq/Duu++O4quYWIY6Z7fcckvW9+5zn/ucaRues9G1fv16nHfeeZgyZQpmzJiBL37xi3jzzTdN25ws3zUGKAAef/xxrFq1Cj/4wQ/wyiuvoKmpCYsXL8Y777wz1odGBmeddRb279+vbrt27VLr7rnnHtx33324//778dJLL6G2thaXXXaZmreJSu/IkSOYN28e7r//ftv1+ZyjVatW4cknn8SWLVuwfft2HD58GEuWLIGu66P1MiaUoc4ZAHz+8583fe9+97vfmdbznI2ujo4OLF++HC+++CK2bt2KgYEBLFq0CEeOHFHbnDTfNUHis5/9rPjGN75hWvbpT39afO973xujIyKrtrY2MW/ePNt1g4ODora2VmzYsEEtO3bsmPB6veIXv/jFKB0hGQEQTz75pLqfzznq7e0VVVVVYsuWLWqb9957T1RUVIhnn3121I59orKeMyGEWLp0qbj66qsdH8NzNvYOHDggAIiOjg4hxMn1XZvwLSiZTAY7duzAokWLTMsXLVqEF154YYyOiuzs2bMH9fX1CAQCuOGGG7B3714AQCqVQk9Pj+kcejweNDc38xyWiXzO0Y4dO3D8+HHTNvX19Zg7dy7P4xhKJpOYMWMGPvWpT2HZsmU4cOCAWsdzNvb6+voAADU1NQBOru/ahA9Q/u///g+6rmPmzJmm5TNnzkRPT88YHRVZnX/++XjkkUfwX//1X/jXf/1X9PT04MILL8QHH3ygzhPPYfnK5xz19PTA7XZj2rRpjtvQ6Fq8eDE2b96MRCKBe++9Fy+99BJCoRDS6TQAnrOxJoTA6tWrcfHFF2Pu3LkATq7v2riczbgUXC6X6b4QImsZjZ3Fixer/5999tm44IILcPrpp+Phhx9WSXs8h+VvOOeI53HsXH/99er/c+fOxcKFC9HY2IhnnnkG11xzjePjeM5Gx4oVK/DHP/4R27dvz1p3MnzXJnwLyvTp06FpWlbUeODAgawIlMrH5MmTcfbZZ2PPnj1qNA/PYfnK5xzV1tYik8ng4MGDjtvQ2Kqrq0NjYyP27NkDgOdsLK1cuRJPP/00tm3bhlmzZqnlJ9N3bcIHKG63GwsWLMDWrVtNy7du3YoLL7xwjI6KhpJOp/E///M/qKurQyAQQG1trekcZjIZdHR08ByWiXzO0YIFC1BVVWXaZv/+/di9ezfPY5n44IMPsG/fPtTV1QHgORsLQgisWLECTzzxBBKJBAKBgGn9SfVdG7P03DKyZcsWUVVVJR588EHxxhtviFWrVonJkyeLrq6usT40+siaNWtEMpkUe/fuFS+++KJYsmSJmDJlijpHGzZsEF6vVzzxxBNi165d4sYbbxR1dXWiv79/jI984jh06JB45ZVXxCuvvCIAiPvuu0+88sororu7WwiR3zn6xje+IWbNmiWee+45sXPnThEKhcS8efPEwMDAWL2sk1quc3bo0CGxZs0a8cILL4hUKiW2bdsmLrjgAnHaaafxnI2hb37zm8Lr9YpkMin279+vbh9++KHa5mT5rjFA+cg///M/i8bGRuF2u8W5556rhmxRebj++utFXV2dqKqqEvX19eKaa64Rr7/+ulo/ODgo2traRG1trfB4POKSSy4Ru3btGsMjnni2bdsmAGTdli5dKoTI7xwdPXpUrFixQtTU1IhJkyaJJUuWiHfeeWcMXs3EkOucffjhh2LRokXik5/8pKiqqhKzZ88WS5cuzTofPGejy+58ARCbNm1S25ws3zWXEEKMdqsNERERUS4TPgeFiIiIyg8DFCIiIio7DFCIiIio7DBAISIiorLDAIWIiIjKDgMUIiIiKjsMUIiIiKjsMEAhIiKissMAhYiIiMoOAxQiIiIqOwxQiIiIqOwwQCEiIqKy8/8BgC5cVmtgBlkAAAAASUVORK5CYII=\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"sellers_spec = [('ZIP', 40)]\\n\",\n    \"buyers_spec = sellers_spec\\n\",\n    \"traders_spec = {'sellers':sellers_spec, 'buyers':buyers_spec}\\n\",\n    \"\\n\",\n    \"order_interval = 10\\n\",\n    \"order_sched = {'sup': supply_schedule, 'dem': demand_schedule,\\n\",\n    \"               'interval': order_interval, 'timemode': 'drip-poisson'}\\n\",\n    \"\\n\",\n    \"n_sessions = 10\\n\",\n    \"\\n\",\n    \"x = np.empty(0)\\n\",\n    \"y = np.empty(0)\\n\",\n    \"\\n\",\n    \"for sess in range(n_sessions):\\n\",\n    \"    trial_id = 'smith_chart_' + str(sess)\\n\",\n    \"\\n\",\n    \"    market_session(trial_id, start_time, end_time, traders_spec, order_sched, dump_flags, verbose)\\n\",\n    \"\\n\",\n    \"    prices_fname = trial_id + '_tape.csv'\\n\",\n    \"    with open(prices_fname, newline='') as csvfile:\\n\",\n    \"        reader = csv.reader(csvfile)\\n\",\n    \"        for row in reader:\\n\",\n    \"            time = float(row[1])\\n\",\n    \"            price = float(row[2])\\n\",\n    \"            x = np.append(x,time)\\n\",\n    \"            y = np.append(y,price)\\n\",\n    \"\\n\",\n    \"plt.plot(x, y, 'x', color='black');\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"And let's introduce some variety into the population of traders, have a mix of different strategies.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 12,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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SqXSSbEAEdIBAABAUsBJNgJYfOgESAcAAABpAEM8vwOLD50A6QAAACANYIhHgMWHToB0AAAAEDdYqK1KsPjQCZAOAAAA4gQ+KFWAxYdOgHQAAABQTyCgMLD40AmQDgAAAOoNnGR/BxYfOgHSAQAAQBqAgPI7sPjQCZAOAAAA0gCcZAEAAABQE+AkG4GhoSGrj8Xw8DBWTwUAAABqCASU34EVVAEAAID0AB+U34EVVAEAAID0AB8UAVZQBQAAAJIhUR+U5557jlatWkXd3d2UyWToqaeest574403UiaToW9961tl5ycmJujWW2+l0047jWbPnk2rV6+mPXv2hA1KIvT393vCSWtrK4QTAAAAoA6EFlDeffddWrx4MT300EO+9z311FP0s5/9jLq7uyuu3XbbbbRhwwZav349vfDCC3TkyBFauXJlKqawYgVVAAAAIAWoKiAitWHDhorze/bsUWeddZbauXOn6unpUQ8++KB37dChQ6qlpUWtX7/eO7d3717V1NSkNm7c6PTd8fFxRURqfHy8muBXUCgUFBGpQqFg/A0AAACA6ITpv2N3kp2amqIvfvGLdNddd9H5559fcX3r1q10/PhxuuKKK7xz3d3dtGjRInrxxRdpxYoVFc9MTEyUbVZ3+PDhuIONFVQBAACAFBG7gHL//ffTjBkz6M/+7M+M1w8cOECtra00b968svMLFiygAwcOGJ9Zu3YtffOb34w7qGVgBVUAAAAgPcQqoGzdupW+/e1v07Zt2yiTyYR6Villfebuu++m22+/3ft9+PBhOvvss6sKq8RvITZYTgAAAIDaEutCbc8//zwdPHiQzjnnHJoxYwbNmDGD3nzzTbrjjjuot7eXiIi6urpocnKS3n777bJnDx48SAsWLDC+t62tjebOnVt2AAAAAGD6EquA8sUvfpFefvll2r59u3d0d3fTXXfdRT/5yU+IiGjJkiXU0tJCmzZt8p7bv38/7dy5ky699NI4gwMAAACABiX0EM+RI0fo9ddf936PjY3R9u3bqbOzk8455xyaP39+2f0tLS3U1dVF5513HhERtbe30/XXX0933HEHzZ8/nzo7O+nOO++kCy64gJYvX15ldAAAAAAwHQgtoPzjP/4jLV261PutfUOuvfZaevTRR53e8eCDD9KMGTPos5/9LB09epSWLVtGjz76KPa7AQAAAAAR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3nmHuru7qanJ38ukIS0oTU1NtHDhwsTeP3fuXBReR5BW4UB6uYO0cgdpFQ6klztJpFWQ5UQDJ1kAAAAApA4IKAAAAABIHRBQGG1tbTQ4OEhtbW31DkrqQVqFA+nlDtLKHaRVOJBe7qQhrRrSSRYAAAAA0xtYUAAAAACQOiCgAAAAACB1QEABAAAAQOqAgAIAAACA1AEBBQAAAACpAwLK73j44Ycpm83SzJkzacmSJfT888/XO0g157nnnqNVq1ZRd3c3ZTIZeuqpp8quK6VoaGiIuru7adasWZTL5egXv/hF2T0TExN066230mmnnUazZ8+m1atX0549e2oYi9qwdu1auvjii2nOnDl0xhln0FVXXUWvvPJK2T1Irw/4zne+QxdeeKG3KuUnP/lJ+j//5/9415FWdtauXUuZTIZuu+027xzS6wOGhoYok8mUHV1dXd51pFU5e/fupS984Qs0f/58OuWUU+hjH/sYbd261bueqvRSQK1fv161tLSo733ve+qXv/yl+spXvqJmz56t3nzzzXoHraY888wz6utf/7p64oknFBGpDRs2lF2/77771Jw5c9QTTzyhduzYoa6++mp15plnqsOHD3v33HTTTeqss85SmzZtUtu2bVNLly5VixcvVu+//36NY5MsK1asUOvWrVM7d+5U27dvV5/5zGfUOeeco44cOeLdg/T6gKefflr9+Mc/Vq+88op65ZVX1F/+5V+qlpYWtXPnTqUU0srGz3/+c9Xb26suvPBC9ZWvfMU7j/T6gMHBQXX++eer/fv3e8fBgwe960irD3jrrbdUT0+P+tKXvqR+9rOfqbGxMfXss8+q119/3bsnTekFAUUp9YlPfELddNNNZec+/OEPq7/4i7+oU4jqjxRQpqamVFdXl7rvvvu8c8eOHVPt7e3qu9/9rlJKqUOHDqmWlha1fv167569e/eqpqYmtXHjxpqFvR4cPHhQEZHasmWLUgrp5cK8efPU//gf/wNpZeGdd95RH/rQh9SmTZtUX1+fJ6AgvcoZHBxUixcvNl5DWpXzta99TV122WXW62lLr5N+iGdycpK2bt1KV1xxRdn5K664gl588cU6hSp9jI2N0YEDB8rSqa2tjfr6+rx02rp1Kx0/frzsnu7ublq0aNG0T8vx8XEiIurs7CQipJcfpVKJ1q9fT++++y598pOfRFpZuOWWW+gzn/kMLV++vOw80quS1157jbq7uymbzdLnPvc5euONN4gIaSV5+umn6aKLLqJ/9+/+HZ1xxhn08Y9/nL73ve9519OWXie9gPLP//zPVCqVaMGCBWXnFyxYQAcOHKhTqNKHTgu/dDpw4AC1trbSvHnzrPdMR5RSdPvtt9Nll11GixYtIiKkl4kdO3bQqaeeSm1tbXTTTTfRhg0b6KMf/SjSysD69etp27ZttHbt2oprSK9yLrnkEvr+979PP/nJT+h73/seHThwgC699FL6l3/5F6SV4I033qDvfOc79KEPfYh+8pOf0E033UR/9md/Rt///veJKH1la0asb2tgMplM2W+lVMU5EC2dpntarlmzhl5++WV64YUXKq4hvT7gvPPOo+3bt9OhQ4foiSeeoGuvvZa2bNniXUdanWD37t30la98hX7605/SzJkzrfchvU7wb/7Nv/H+v+CCC+iTn/wk/d7v/R79z//5P+mP/uiPiAhppZmamqKLLrqI7r33XiIi+vjHP06/+MUv6Dvf+Q5dc8013n1pSa+T3oJy2mmnUXNzc4Xkd/DgwQop8mRGe8X7pVNXVxdNTk7S22+/bb1nunHrrbfS008/TZs3b6aFCxd655FelbS2ttLv//7v00UXXURr166lxYsX07e//W2klWDr1q108OBBWrJkCc2YMYNmzJhBW7Zsob/6q7+iGTNmePFFepmZPXs2XXDBBfTaa6+hbAnOPPNM+uhHP1p27iMf+Qjt2rWLiNLXbp30AkpraystWbKENm3aVHZ+06ZNdOmll9YpVOkjm81SV1dXWTpNTk7Sli1bvHRasmQJtbS0lN2zf/9+2rlz57RLS6UUrVmzhp588kkqFouUzWbLriO9glFK0cTEBNJKsGzZMtqxYwdt377dOy666CL6kz/5E9q+fTude+65SC8fJiYm6Fe/+hWdeeaZKFuCf/Wv/lXFcgivvvoq9fT0EFEK261YXW4bFD3N+JFHHlG//OUv1W233aZmz56tfvvb39Y7aDXlnXfeUS+99JJ66aWXFBGpBx54QL300kvedOv77rtPtbe3qyeffFLt2LFDff7znzdOP1u4cKF69tln1bZt21Q+n5+W0/Vuvvlm1d7erkZHR8umN7733nvePUivD7j77rvVc889p8bGxtTLL7+s/vIv/1I1NTWpn/70p0oppFUQfBaPUkgvzh133KFGR0fVG2+8of7+7/9erVy5Us2ZM8drv5FWH/Dzn/9czZgxQ/3H//gf1WuvvaYee+wxdcopp6j/9b/+l3dPmtILAsrv+K//9b+qnp4e1draqv7wD//Qmy56MrF582ZFRBXHtddeq5Q6MQVtcHBQdXV1qba2NvXpT39a7dixo+wdR48eVWvWrFGdnZ1q1qxZauXKlWrXrl11iE2ymNKJiNS6deu8e5BeH3Ddddd59ev0009Xy5Yt84QTpZBWQUgBBen1AXqdjpaWFtXd3a3++I//WP3iF7/wriOtyvnhD3+oFi1apNra2tSHP/xh9d//+38vu56m9MoopVS8NhkAAAAAgOo46X1QAAAAAJA+IKAAAAAAIHVAQAEAAABA6oCAAgAAAIDUAQEFAAAAAKkDAgoAAAAAUgcEFAAAAACkDggoAAAAAEgdEFAAAAAAkDogoAAAAAAgdUBAAQAAAEDq+P/QogXRltvOxwAAAABJRU5ErkJggg==\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"sellers_spec = [('ZIP', 10), ('ZIC', 10), ('SHVR', 10), ('GVWY', 10)]\\n\",\n    \"buyers_spec = sellers_spec\\n\",\n    \"traders_spec = {'sellers':sellers_spec, 'buyers':buyers_spec}\\n\",\n    \"\\n\",\n    \"order_interval = 10\\n\",\n    \"order_sched = {'sup': supply_schedule, 'dem': demand_schedule,\\n\",\n    \"               'interval': order_interval, 'timemode': 'drip-poisson'}\\n\",\n    \"\\n\",\n    \"n_sessions = 1\\n\",\n    \"\\n\",\n    \"x = np.empty(0)\\n\",\n    \"y = np.empty(0)\\n\",\n    \"\\n\",\n    \"for sess in range(n_sessions):\\n\",\n    \"    trial_id = 'smith_chart_' + str(sess)\\n\",\n    \"\\n\",\n    \"    market_session(trial_id, start_time, end_time, traders_spec, order_sched, dump_flags, verbose)\\n\",\n    \"\\n\",\n    \"    prices_fname = trial_id + '_tape.csv'\\n\",\n    \"    with open(prices_fname, newline='') as csvfile:\\n\",\n    \"        reader = csv.reader(csvfile)\\n\",\n    \"        for row in reader:\\n\",\n    \"            time = float(row[1])\\n\",\n    \"            price = float(row[2])\\n\",\n    \"            x = np.append(x,time)\\n\",\n    \"            y = np.append(y,price)\\n\",\n    \"\\n\",\n    \"plt.plot(x, y, 'x', color='black');\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"Everything we've done so far has had a single static supply and demand schedule. But in real markets, the supply and demand schedules are constantly varying -- often by only small amounts, but occasionally there might be large \\\"shock\\\" changes.\\n\",\n    \"\\n\",\n    \"Let's introduce a shock, part-way through the session.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 13,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter\": {\n     \"outputs_hidden\": false\n    },\n    \"pycharm\": {\n     \"name\": \"#%%\\n\"\n    },\n    \"tags\": []\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAAAigAAAGdCAYAAAA44ojeAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABgEElEQVR4nO2dfZBcVZn/n56e6R6ISXdCSCYh0N0o6moguImrYYnTuYNByoAvW8q66xpf1hUlrBRYu8L+pqfpRpLdqtVyyxVrVVAWt+IfgMUuiITpzBCWddUEigR3Ec0EAiSbEpmZAEk36Tm/P+JzOff0OfelX+90fz9VtyZ9+76c+9ybPt/7PM95TkQIIQgAAAAAIET0dboBAAAAAAAqECgAAAAACB0QKAAAAAAIHRAoAAAAAAgdECgAAAAACB0QKAAAAAAIHRAoAAAAAAgdECgAAAAACB39nW5APczNzdELL7xACxcupEgk0unmAAAAAMAHQgg6duwYrVy5kvr63H0k81KgvPDCC3T22Wd3uhkAAAAAqINDhw7RqlWrXLeZlwJl4cKFRHTqAhctWtTh1gAAAADAD7Ozs3T22Wfb/bgb81KgcFhn0aJFECgAAADAPMNPegaSZAEAAAAQOiBQAAAAABA6IFAAAAAAEDogUAAAAAAQOiBQAAAAABA6IFAAAAAAEDogUAAAAAAQOiBQAAAAABA6IFAAAAAAEDogUAAAoMPk83kqFova74rFIuXz+fY2CIAQAIECAAAdJhqNUi6XqxEpxWKRcrkcRaPRDrUMgM4xL+fiAQCAbmJ0dJSIiHK5nP2ZxUmhULC/B6CXiAghRKcbEZTZ2VlKJBI0MzODyQIBAF0Di5JYLEaVSgXiBHQdQfpvCBQAAAgR8XicKpUKxWIxKpfLnW4OAE0lSP+NHBQAAAgJxWLRFieVSsWYOBsGkNgLWg0ECgAAhAA556RcLlOhUNAmzoYFJPaCVoMkWQAA6DC6hFhd4myYaDSxN5/PUzQa1W5XLBapWq3CC9PjQKAAALoOt85v48aNRES0a9eumu861TFWq1Vtp86fq9VqzT6d6uD5vNVqlaLRqO3pufnmm6lSqVA2m7W3czv/5OQkTUxMEJFTfLHI4eO0kk7YsB3n7BbxhxAPAKDrcAs/TExM0MTERKhCE/l83uhxGB0d1XYmnQqx8Hl3795te084Z4aIqK+vz9f5LcsiInJcA7dd/r6VdMKG7Thn14TfxDxkZmZGEJGYmZnpdFMAACGlUCgIIhKFQqHms9t37WZsbMx43kKhIMbGxoz7WZalvQ7Lsoz7NQP5PERUs/i1YzabtfeJxWKO/d2uvVmMjY2JdDpttGE2m21JG9rx/KnHZFvrzlEoFMTw8HBdz2FQgvTfECgAgK6Ff6S585N/gN2+60Qb1fN7dVqqSODrUEVLq9vNSzQaDSxQ1GOYBGS7rkG1YSvb0I7nTz2H23Nmem6afS8gUAAA4Pfwj3NfX5/9Jsg/tvxdNBq117f6rV1HvW/UvB2LA/7byo59bGxMZLNZrfckGo3WeCTcjpNKpUQymXQcg4+bTCbF8PBwS9rObZM9KLxEIhH73+l0uqXPAz9/sVisLedwe87a5ZGDQAEAAKF/g+QOiX+MuVPPZDKCiEQ2mw1FW/2KDLWDtSzLccxmd7Amz0nQjl0O75gW+Vqa3XaTyNK1oZVhnlZ6UNjG8jn4vHy/+BlJJBKO/we8D39OpVJNaRMECgCg5zG9LcoL//jy306GeoQI/kZtEgutDpPI9lLt51dYqOJAFjjsQWkFqs1UD47Om9NsG7YzB0X3PLCtI5FIzbbyvZDvSbPEIgQKAKCn4TdH/lF1C0uoHWPQTqLeJFd1X/WN2uvN3ZSoqootOazVDE8An9fUsfP5vRJdvTwozfRkqaEdnVg1Lc0UDbowCqOur+e54n3YtqlUyr4fnPRr8lK5eZOa6cmCQAEA9DTyD7H8g+22JBKJQIJCPZcqKLgTdOtoTQmK/NmtYxgeHnZ0Pur1pNPpmuPLnbSuLdx+t84xm83ao1tUccc2kG1uOg5vp4aoZIHSDFGl5plwe9S265Z0Om20kZ/zmhJOM5mM9lmRnyGv5GndvVTFIz8fg4ODjuvq7+93rGfPm0l0eonNIECgAAB6Hvkt2Y/nJJPJ+D6mbjSQLChU97obqhjxGlXhtR8v3NnIx/E7YsjPdjovhNoWv0m+6tLMkJupnV7iRD1/0DCMaXvTfdMd1+2+eB3fJE5UG+vCOSZbNcObBIECAAAimCtf7QhMb4teuS1uQzp1yG5/NWHSrR3yfib3PXc6/D0vQcWI+tmUsyC/jbP3Qb0G+XO7wjxBnwNeBgcHbU+IfO1+PQkmG/J9kxNVZbLZrJ1o7Bb64+/YW2Y6vrrE43GtSHHLx2nWvYBAAQCA3yMLBlMnJH/mH2n5B5lDFmrHIAsKtbNVvSxenZouQdZPHoKXN0DtpDg0oBNE6vnU7VKpVM35ksmkUQCwLbnzlMWRvE88Hq9JtOWO1rKspgw3DiJS5GdCFhFyfk3Q86q2dntW5OsXwjkcXt1evR9BQlh8DvXZ1QmVZuXiQKAAAIDw3yllMpmaXAidh0T+kVYFhamj8BMaMHVi9YZa3BY+lk4Q6c4nCzy5Ronur6kD1NmQO8VMJqN9408mk44wVTPQddrsTVDFiSxSotGoY8RXUFRb6+6Zei/VEB2LE50t5CJ5LOqCPA+6Z1c+JlFtPk69QKAAAHoe9U20EU+D3IGY3O6mzpn/mkqJc0fNHhtVfHiFZPwkAMvtyWazIpVKaQXR2NhYzSgck024o3YTJ6pXhEMRw8PDNaNq1OPUI06Gh4cdiboybu2UBYAqTtQ2cXuDhnnUZyWbzRrbFI/HRTqdtkWzHKqTnxX5+F4ek76+vprPXPvE6//C4OBg04rmQaAAAHqaenMOTIsuvs8doCpOTMN+dUmvOne+ul4+t8nDEuSN2XRd8pu0rq6JvI/6Vh900SXuyqJEtl0Q1PaznXTH1dlCt15ttx+PmHof1WdF9Sr5WeRKsKZnMujCo3m8nl2/1+sHCBQAQE8j171QOwL1TVK3yG+QkUjEfpPVlXGXPRj8vdpxc1vU+izyZ/47PDxsH0d+U2ZxEolE7OvjtvjJRXETJqpQkrfla5HryOhCAEEW3X0xDTdWE1Plf+s8JewVMIWfOFQhr0+n07Y91aG3ukWtlKvzqOiEjFoHxc37JYee1HmO5H35GTHdf9N1qOLEtMg5Ks0QKRAoAICewSuRVO7wG110tSfkOhsmlzl/LxfOkjuAsbExrbtfFTbyPhymkYWDl0hJp9MiHo87QhVEr3tm2JWv2iuZTDqmCAgSVtJ1eH470WQy6eiIub1qOCyVStnhIy8bsPdCriPDC3/2I75UL5Y6yqUZCc6meygLVK+S/V6hH6/Ql2x71EHxAQQKAIDxSiT1GnLpd3ELN/h115s6Ej+dhNqJurnj/bZFiNpRTtwW3Rw78jl11+LV4aptjEQi2lFWphE9qjjQ2d6PQJGPoYoRP6JBFXi658/vc+t1Hjc7qoJM/neQ5113nlaUuReihQLlm9/8pjj//PPFwoULxcKFC8W73/1ucf/999vfb9mypeYi3/WudzmOceLECbF161ZxxhlniNNPP11cfvnl4tChQ0GaAYECAHBgShw15YnUu7h1Qn46Z7e3Zj+hJ377V0NDQZZkMmnvx25+7oz4s+pJ0CWN6jrAIELLqwN1Kxwml+63LKvG46OOzFE7dg7zNJJLIwuremqEcJv92EwNOcrPYiqVqrle+Xq87Own1NPMaQdaJlDuvfdecd9994mnnnpKPPXUU+LGG28UAwMDYv/+/UKIUwLlfe97nzh8+LC9vPjii45jXHXVVeKss84SO3fuFHv37hUbN24Ua9asESdPnmzJBQIAegM1XME/4o0mzEYiEW1tFBVTmEbuhPyGYnRLNBq1ryWRSNh1WYJeXzqd1oaiuFNjoaSKk/7+fm1H7lYHxW2px5uk2pE/p9Npz3o3bvaQn596FrV0vfxMmsIiuhBTkGdBFbtsC7XoWhDRaLpPzQjtMG0N8SxevFh85zvfEUKcEigf+MAHjNtOT0+LgYEBsWPHDnvd888/L/r6+sQDDzzg+5wQKAAAHXK9iSCufz8dhVfpea8OTh1Z0kiSqXycZo9YkhfdcFNdO5rhofIbktB1vI2E8eT7Wa9Hitugex7qfV78nlf37OpmhvZzTFPYsFkjeIQI1n/3UZ1Uq1XasWMHvfLKK7R+/Xp7/cTEBC1btoze/OY302c/+1k6evSo/d2ePXvotddeo02bNtnrVq5cSatXr6ZHH33UeK5yuUyzs7OOBQAAmHw+TyMjI1SpVCgWi1GlUiEiomw2S0REkUiESqWS/W8iong8Tul0mrLZLE1NTXmeI5vNUqFQoGq1qv2ej29ibm6OLMuiarVKIyMjxuP4IZvN0ujoKBWLRcrlckT0+nUxmUwm0DGj0WjNOiGE/e/BwUE6ceKE43vLsiiXyxmvXW2TG/K5TO0hIpqennb8JTpl+0KhQH19wbs0bnuxWKTf/OY3gfefnp6mZDJJpVKJisUiERGNjIxQLpeznz8mn8/b25RKJUqlUmRZlu9z9ff315w3lUpRKpVybMe2zGazlMlkHLZyg23Btp+amrKf2Y4QVP088cQTYsGCBSIajYpEIiHuu+8++7sdO3aI//iP/xD79u0T9957r1izZo14+9vfLk6cOCGEEOIHP/iBo2oh8973vlf81V/9lfGcY2NjWrUHDwoAQAjhGGEihLk+iBpiCfr2rw4vZYK8DcshE6Ja17yfRa2jUW/oyFSQrN5tm5Xr43fUlew9COo9kduqnq+e0IvqxUmn045S/+rcSfLfZoRhdOv9eOnUHBQ5bMbrOuVBCSxQyuWyePrpp8XPf/5z8eUvf1ksXbpUPPnkk9ptX3jhBTEwMCDuuusuIYRZoFxyySXic5/7nPGcJ06cEDMzM/Zy6NAh3xcIAOhuVHHglhirVi9Vf5T9LLofa05aNSU+qqKEOzFdWXWvJZlMOoaZqqEn1R6mjttvHQy/i1xLpN7ciqD3g4cW664xSNhOXVfPdQwODtaU6pf/qkXkOLejEZElP3Ne4jCbzRqvxxS6Mw2hboS25qCMjIy4ej/e9KY3ie3btwshhBgfHxdEJH73u985trngggtELpfzfU7koAAAGO6s5R9oOWEyHo87amioRdb4x9dU28NPNU11VImuk+VOQB3GaxIvprdf7pRTqZQjUVaG64L49Wg0mg8zODho1xYxVW/1s2QyGWONErd9VIFRzzUkEgm77WxTfmbqHaI+ODgoUqmUMYFVfkZNI4+8FrdnX7YJX0s6nXa0iRf5GuV5d5pV/4Rpq0CxLEts2bJF+91vf/tbEY/Hxfe//30hxOtJsj/84Q/tbV544QUkyQIAGsIU0lGT/NwSF2XPg65DClLa3JS0qb5Ne3W2pg7ET5tamTyruyadnetZZGFgsofuPsvnDerBcXse3EaC+fFCNRq+cVt0k/y5edBMtYL8PlPNoGUC5YYbbhAPP/ywmJqaEk888YS48cYbRV9fn3jwwQfFsWPHxPXXXy8effRRMTU1JXbt2iXWr18vzjrrLDE7O2sf46qrrhKrVq0SDz30kNi7d6+wLAvDjAEADcOVVXU/uFxCXgj3suREZm+C3Pmy50JFnqzO1EnykFTdebw6drU8u5/r4Tdzk4eo3jd37vzk48pv6kE9GfL27PEaHh7WCjN1oj31jd9PZ+7WKatCtt6qr17PVDMWWfSa6uPopmhgdCKnlbRMoHz6058WqVRKxGIxceaZZ4qRkRHx4IMPCiGEePXVV8WmTZvEmWeeKQYGBsQ555wjtmzZIp599lnHMY4fPy62bt0qlixZIk477TSxefPmmm28gEABADDsjjcJAj+z4qphIlOn6FU5VH2DV9+e1TBOox2TbnZbLoMvlyd3yz9oxiKLQFN9DtOiViyVxZ+farWZTEYkk0mRSqVqkp5VO7uJDPn5kMNmHAYMWt4/SF4R0Smh6Hcf+bpSqZR9XXLRNnWahEwmU5PkLV+Trn5QM0M7DErdAwB6BtMbs/wj7mdW3CBv/n4qytbr2vezn7qNmhisirFGvBl+FlPpeb+iSFfG3k+YSD6+ei4+jpsnS93PVMtEbasQwpeY8FMdOKidTM+HKtLla/Gyrzr6zc9zXi8QKACAnoJd2KZwBXtHksmkHeqR0YkT0xBkr3lJ3MI7ukXX4cTj8UBJokKYxUmQgnWNLHI4RPZGycNt1XazZ0KuiMtJwHJ7dd4LNyGnVodlscrPhyrodENq5WeC92NbN2vyST4m/9s02SS3gz0auhmaTfkk8no5FGYaBSbbpBVAoAAAego3UaDO1aIrSy6PwpFDI4VCoWZeE3lbt/YE6aR4xI3aQXmJFN0IFl1b+PqDhnncRACLED62aTZfVTjx9roOUA5ZyUPC6xFVcsiCw2HyKCNGDoNw23hf3SzU6iiZZoXr1BCiTmyoo4uCLvK1y2EsPh5fW7PL28tAoAAAegr+gfVKRgxSutsr2dJPmKeejsN0Dbr16nnc8GqT2/emc6u2Um3iFXLSCSr1WF6dsU50ye31E96Tz8P7ysfgtnAHbprhuZHFLXfGdC71vsj7qd95PfPyNBGtBAIFANC1yF4OeZ1XRxF0XhG5Y+QkTLVz5rdydZSQfD6vye9kb4zaSXJowe8oEK9EYDVvQg6JmWYENlU9VT0gOq8S20aHbDOT7dUZg00eIDcvRpA8Cl3lYdPQca7ZEuT+mJZ0Oi2Gh4cd18jHlO+LKrx0zzwnwwaxg2rvVo7kgUABAHQdOve2KQTgFu7x47qWcx5MAkMVIHIegOxl8fIAqAmKXmEN3XpdKEXFa5STvK9a9VSXl9HqjkwdVeLHU6FLlPXbTpMHpVAo2B2+zisRVJzI9lZryKj30PTsBBkhJLdPF4YzVSJuVZgHAgUA0HWYCmcFrSTqp7OSEwiFEDVv6Dw6Q+1g5PwUPo+fUTm6Dl+XV8PtUddzx+OVKOtW80QegqrOG6Mey08eTiNwe9nOpnvqNUpG9nL48SDweeRcDPWYupmygy7yaBxOFlbvMdPI8HC+DlM15HpCcI0CgQIA6EpMIkX+8ZU7FfVNM5lMBj6Xnw5C7tw5cdRvcS927+uSN/l7OXm2UCjY4Sa1bgifXw2dyG1Rr4enAjDZoFUixIQpB0UeSeNmz8HBQSHE6x07ixSvpGaTJyGZTNYkLxcKhbqHkavDf/leydMu6OzBi5vHRg3Z8TlkISTbAR6UFgCBAkDvostP4M+6AmHqD7rfpEkhgr29quJIt68pVGESJ/L6RmpUqB4Ctgl7hlrxplwPXsm2bFOvkTO8vyxSGjmvLC7chIfbvddNCRDEHn7r86j/J+S2mc4b1hyUfgIAgJCTz+cpGo3S6OgojY6OUj6fp0ql4timUqnQb37zG4rH43TaaafR9PQ0RaNRqlarFIvF6OKLL6ZHH32UpqamqFgs0ujoqOs5i8UiTU1NUSQSISGE67bJZJK++tWv0vT0NBERFQoFGh8fp5deeokSiQRlMhmyLMtu/8jICB04cIDS6TQREVWrVcfxqtUqFQoF+1r5OvhvJBKh0dFRKhaLjvX8N5/P1xzPsiwqlUr231gsRpVKhTKZDJVKJV82aTXydcts2LDB/rt7924qlUqux7ntttuoWq3SgQMH6Nxzz6W5ubm6zpvNZu1zsd3U54E/z83NUaFQICKir3zlKzXnuPDCC6mvr49KpRLddtttvmzN7VKfDyKidDpNBw8erLlubsNNN91ElUqFYrEYjY+P28+KjtHRUbr55pvt7Tv9HDAQKACA0BONRimXy9mf1Q6HO49nnnmGiIjWr19vdwbcEWezWc8fahm5U/eChQm3hehUxzU9PU3XXXddzQ/++Pi46/FkgcHXnkwm7XYLIejcc8+lqakpymQyjr/cQanH42OWSiW7My4Wi5TL5ciyLF82aTWqsFLXF4tFKpVK2s6ZrzuXy9HBgwcpGo0SEdGBAwfqPi8LBD6uKk6SySS99NJLDjsSEZXL5ZpjTUxM2Mfya2tu18jISM1zqF5/Mpl0rGNhXqlUPMVnsVi0xYmf7dtGy/w4LQQhHgB6D68iVrIL3BRXrycsEiTME4lEtKOMGoXbwDk16l8/8w2ZbFCPbTqBV/6RfN9bcT2mmiNu9Vp0bQ3aLt3+cm6VZVna/CK/z74p56dVzwNyUAAAXYeuA9ANL+Yf70Y6Ynnb4eHhukZSmBJP671ur6RMr9Lk8sgi3TnanQwbFN0wc7XKLz8Tzb4etQaKfC75mdKVzBfC+ewGfS74mHJNFt19l/8vqOcIKk5bKVKQgwIA6DrY3X7TTTfZLvJsNkuPPPIIVSoVikQiNDU1RURk53vI8Ge/4R05JyGXy2nDCm709fU5Qiv1ooYZTHz60592PY5bO0LhzveA279x40YiopowlRCCotEobdiwoanXw2ElDqGpuTxyeGzLli00OTlZ8/zxv0ulEg0PDwc6fyqVonPPPdcOC/IzwHlVfO7x8XHKZDJERLRr1y7HMUzPvin3Jsj/lZbSdHnUBuBBAaA34Tc71d2uK0vezPPpwkd+lla0pR3nCivNHt3k93xuQ3Hbaft2jrZpFfCgAAC6Dn5T5jc+ThIlat2bnjyKYm5uzk68ZZLJpCNBlohocHCQTpw40dR28LXzW7xKJpOx36zngzekXtQ3fvmZIDrloWimHeT7n81m7WPKHoZsNtsWT4P6/PNnuT1dRxsEU9OBBwWA3sKUyCfXw5ArfLbizVL3pu6WrNmstqjJumouilyRtFXXHkbme9JvELrpWuFBAQB0Feqbs24IMNdFMdWNaEYbstksEb0+lJiH/6peFG5XM96u5WuVPSg8JHR6etqRH9HxvIE2Efr8iSbSS9cqExHCowJRCJmdnaVEIkEzMzO0aNGiTjcHANBi5EJtRKcSJScmJojolFiYm5tzfN6wYUPDyal+2nTHHXc4apBwoTQWLbpOpd5zRaNRKpVKdj0N2c2fzWZtcdLq6wagEYL0331tahMAANQNFysrFotULBZtMcJVUC3LcuQh7N69uy1tksWJZVl08uRJymQytlejWbkBLDpkcUJ06g26UCjY9oA4Ad0EQjwAgNCjDvdNpVI0MzNjCwMuH09EjoqrrURXPj4ej9vl4/2W1A9yvl5084PeBSEeAECokcM7yWSSZmZm7O84lKLORWNZlracPJe5b5anQW4bi5NYLEblcrnp5+oF1FCeDOzZHSDEAwDoGuTwztq1ax3fcXIqew+q1apj8jsZztfgOVqaQT6ft3NBdHOZoDMNhnyvZVpx78A8oMUjiloChhkD0FvoCqbplkwm49i+HfOLtHsuk24H9uxuMBcPAKDrYHGiVpHlxTR5WyurbnZTfYow0Q0VU4GeIP03clAAAKFHdvFXq9Waae8ZTlblZFI1L6TZIGeidbT63oHOgBwUAEBXwROhcSKsTpzIQ46r1ao2L6TZcA6KDuSg1E877h0IPxAoAIDQI9cckYfTJpNJ+9/8PddB4XlLyuUyFQoFbfIlCB/ynDO4dz1Oi8NNLQE5KAD0DqYEWZ6DxrIsx3emOWmQFxJ+kNPT/WAuHgDAvIfzO+QCZXIdlOnpabusPZeBTyQSdM4559CnPvUpFDSbh6AYHZBBkiwAIJSo08szfX19JISgSCRCc3Nzxu0AAOEjSP8NDwoAIHTk83manJwky7Iol8sREdnl7PmdSghB/f39xrduAMD8Bh4UAEDoYK8I0etDhzncw/BQ42g0SidPnuxUUwEAAcAwYwDAvIZn6SU6NTtxJBJxiBPLsmxxUq1W7YkCAQDdAwQKACCUyCJFdvTyUOJCoUAnT560PSwYhgpAd4EcFADAvCESidDU1BRZlmXnnIyPjztCQshFAaA7gEABAIQSWXQwQgjHbMUsRjAMFYDuAwIFABA68vk8ff/737c/c6gnl8vR1NQUpdPpGjECzwkA3QUECgAgdOzevZsOHjxIROQYQjwxMUGlUokOHjxI0Wi0gy0EALQaCBQAQOjYsGEDHThwwBYpRKdCPjwZ4NzcHMI5AHQ5qIMCAAgtnIfCs9qiIBsA85sg/TcECgAg1MTjcapUKhSLxahcLne6OQCABkChNgBAV1AsFm1xUqlUUOsEgB4CAgUAEErkSQDL5TIVCgXK5XIQKQD0CEiSBQCEDt0MxfwXBdkA6A3gQQEAhI7x8XFKp9M160dHR8myLLrtttson8+3vV0AgPYBgQIACB0jIyN08ODBmpAODzVGHRQAuh+EeAAAoUMO58jl7vnfGG4MQPcDgQIACBX5fJ6i0ahRpGSzWYgTAHoACBQAQKiIRqOORNibb76ZKpWK/b1lWZ1qGgCgjUCgAABChew5ue222xziRKZYLFK1WkWyLABdCpJkAQChg0fryHPxsOckl8vRyMgI5XI5JMoC0MVAoAAAQgeP1pHJZrNUKBSIiOxJA5GLAkD3ghAPACB0VKtVSqfTdPDgQerr66O5uTl70kAionQ6TRs2bECYB4AuBh4UAEDoiEajdPDgQSoUCg7xwfPyTE1N2cm0CPMA0J3AgwIACBW6MvcTExN2yKdSqdDIyAiVSiXUQwGgi4EHBQAQKqrVqkN4cD4KJ8lGIhHkoADQA0SEEKLTjQjK7OwsJRIJmpmZoUWLFnW6OQCAFqF6U+LxOFUqFYpGozVCBgAQfoL03/CgAABCiyxCisWinYNSrVbJsiyqVqudbiIAoEVAoAAAQks+n7fFCXtSyuUyFQoFKpVKSJAFoItBkiwAINTokmblarPyZwBA9wCBAgAILfl8niYnJ425JtlsFmEeALoUhHgAAKElGo3SxMREzXr2qliWhSJtAHQp8KAAAEKLLpSjC/kAALoPDDMGAIQeFiWxWIwqlQrECQDzlCD9NwQKAGBewDVQYrEYlcvlTjcHAFAHqIMCAOgq5BoolUqFisVip5sEAGgxECgAgFCjq4GSy+UgUgDocgIJlFtvvZUuuOACWrRoES1atIjWr19PP/7xj+3vhRCUz+dp5cqVdNppp1E2m6Unn3zScYxyuUzXXHMNLV26lBYsWEBXXHEFPffcc825GgBAV2GqgQKRAkD3E0igrFq1irZv306/+MUv6Be/+AVZlkUf+MAHbBHyD//wD/TVr36VvvGNb9DPf/5zGhoaove+97107Ngx+xjXXnst3XPPPbRjxw565JFH6OWXX6bNmzejlgEAoIbx8XHtpICjo6NkWRaNj493qGUAgJYjGmTx4sXiO9/5jpibmxNDQ0Ni+/bt9ncnTpwQiURCfOtb3xJCCDE9PS0GBgbEjh077G2ef/550dfXJx544AHf55yZmRFEJGZmZhptPgAgxBQKBUFEolAo+FoPAAg3QfrvunNQqtUq7dixg1555RVav349TU1N0ZEjR2jTpk32NvF4nIaHh+nRRx8lIqI9e/bQa6+95thm5cqVtHr1ansbAABgdOEc1EEBoDcIXKht3759tH79ejpx4gS94Q1voHvuuYfe9ra32QJj+fLlju2XL19OzzzzDBERHTlyhGKxGC1evLhmmyNHjhjPWS6XHcMKZ2dngzYbADBPkYu13XzzzaiDAkCPENiD8pa3vIUef/xx+ulPf0qf//znacuWLfTLX/7S/j4SiTi2F0LUrFPx2mbbtm2USCTs5eyzzw7abADAPGZ0dNQeYhyLxSBOAOgBAguUWCxGb3rTm2jdunW0bds2WrNmDX3961+noaEhIqIaT8jRo0dtr8rQ0BBVKhV66aWXjNvouOGGG2hmZsZeDh06FLTZAIB5DOqgANB7NFwHRQhB5XKZMpkMDQ0N0c6dO+3vKpUKTU5O0kUXXURERGvXrqWBgQHHNocPH6b9+/fb2+iIx+P20GZeAAC9AeqgANCbBMpBufHGG+myyy6js88+m44dO0Y7duygiYkJeuCBBygSidC1115Lt9xyC5133nl03nnn0S233EKnn346/dmf/RkRESUSCfrMZz5D119/PZ1xxhm0ZMkS+tKXvkTnn38+XXLJJS25QADA/CKfz1M0GtVODFgsFqlardoihYgQ7gGgSwkkUP7v//6P/uIv/oIOHz5MiUSCLrjgAnrggQfove99LxER/c3f/A0dP36cvvCFL9BLL71E73rXu+jBBx+khQsX2sf42te+Rv39/fTRj36Ujh8/TiMjI/S9732PotFoc68MADAviUajtvhgMWKaxRj1kwDoXjBZIAAgdOg8JxhaDMD8B7MZAwDmPSxKODEW4gSA+Q8ECgCgK4jH4/boHbkWEgBgfhKk/8ZsxgCAUIKhxQD0NhAoAIDQgaHFAIDApe4BAKCV6BJi5XL38mcAQPcCgQIACBXy0GIZDC0GoLdAkiwAAAAA2gKSZAEA85Z8Pm/MNSkWi5TP59vbIABAR4BAAQCECq4kq4oUzk1B1WkAegPkoAAAQoUuIRaVZAHoPZCDAgAIJagkC0D3gUqyAICuAJVkAegukCQLAJj3oJIsAL0NBAoAIHSgkiwAAEmyAIBQgUqyAAAiCBQAQMhAJVkAABFCPAAAAAAIIRAoAIBQgUJtAAAihHgAACEDhdoAAESogwIACCko1AZA94FCbQCArgCF2gDoLlCoDQAw70GhNgB6GwgUAEDoQKE2AACSZAEAoQKF2gAARBAoAICQgUJtAAAiJMkCAAAAoE0gSRYAAAAA8xoIFAAAAACEDggUAAAAAIQOCBQAAAAAhA4IFAAAAACEDggUAAAAAIQOCBQAAAAAhA4IFAAAAACEDggUAAAAAIQOCBQAAAAAhA4IFAAAAACEDggUAAAAAIQOCBQAAAAAhA4IFAAAAACEDggUAAAAAIQOCBQAAAAAhA4IFAAAAACEDggUAEDoyOfzVCwWtd8Vi0XK5/PtbRAAoO1AoAAAQkc0GqVcLlcjUorFIuVyOYpGox1qGQCgXfR3ugEAAKAyOjpKRES5XM7+zOKkUCjY3wMAupeIEEJ0uhFBmZ2dpUQiQTMzM7Ro0aJONwcA0CTy+TxFo1FbgLAoicViVKlUKJvN0q5duzrcSgBAvQTpvxHiAQCEBjW0Mzo6aosTIiLLsjrZPABAG0GIBwAQGtTQDhHZ4gQA0FtAoAAAQoVOpBQKBcc65KAA0P1AoAAAQk0sFnMIEogUAHoDCBQAQOgolUpERHb+SbFYpNHRUVuUVKvVTjYPANAGIFAAAKGiWCzSxMSEPZyYR/IQkUOkAAC6GwgUAEBo0NU60dVEAQB0PxAoAIDQUK1WtYXYENoBoPdAoTYAAAAAtAUUagMAAADAvAYCBQAAAAChAwIFAAAAAKEDAgUAAAAAoQMCBQAAAAChAwIFAAAAAKEDAgUAAAAAoQMCBQAAAAChAwIFAAAAAKEDAgUAEBry+TwVi0Xtd8VikfL5fHsbBADoGBAoAIDQEI1GKZfL1YgUnkQwGo12qGUAgHaDyQIBAKFBN3OxboZjAED3E8iDsm3bNnrnO99JCxcupGXLltEHP/hBeuqppxzbfPKTn6RIJOJY3v3udzu2KZfLdM0119DSpUtpwYIFdMUVV9Bzzz3X+NUAAOY9o6OjVCgUKJfLUTwehzgBoEcJJFAmJyfp6quvpp/+9Ke0c+dOOnnyJG3atIleeeUVx3bve9/76PDhw/Zy//33O76/9tpr6Z577qEdO3bQI488Qi+//DJt3rwZU6kDAIjolEiJxWJUqVQoFotBnADQgwQK8TzwwAOOz7fffjstW7aM9uzZQ+95z3vs9fF4nIaGhrTHmJmZoe9+97v0r//6r3TJJZcQEdGdd95JZ599Nj300EN06aWXBr0GAECXUSwWbXFSqVSoWCxCpADQYzSUJDszM0NEREuWLHGsn5iYoGXLltGb3/xm+uxnP0tHjx61v9uzZw+99tprtGnTJnvdypUrafXq1fToo49qz1Mul2l2dtaxAAC6EznnpFwu2+Ee0+geAEB3UneSrBCCrrvuOrr44otp9erV9vrLLruMPvKRj1AqlaKpqSkaHR0ly7Joz549FI/H6ciRIxSLxWjx4sWO4y1fvpyOHDmiPde2bdvopptuqrepAIB5gi4hVpc4CwDofuoWKFu3bqUnnniCHnnkEcf6K6+80v736tWrad26dZRKpei+++6jD3/4w8bjCSEoEolov7vhhhvouuuusz/Pzs7S2WefXW/TAQAhpVqtahNi+TPy1ADoHeoSKNdccw3de++99PDDD9OqVatct12xYgWlUil6+umniYhoaGiIKpUKvfTSSw4vytGjR+miiy7SHiMej1M8Hq+nqQCAeYRbITZ4TgDoLQLloAghaOvWrXT33XdTqVSiTCbjuc+LL75Ihw4dohUrVhAR0dq1a2lgYIB27txpb3P48GHav3+/UaCA7gWVQ08BO5wCdgAAMIEEytVXX0133nkn/du//RstXLiQjhw5QkeOHKHjx48TEdHLL79MX/rSl+i//uu/6ODBgzQxMUGXX345LV26lD70oQ8REVEikaDPfOYzdP3119P4+Dg99thj9PGPf5zOP/98e1QP6B1QOfQUbIeRkRHHerbD7t27e6JznpycdH0eJicnO9QyAEDbEQEgIu1y++23CyGEePXVV8WmTZvEmWeeKQYGBsQ555wjtmzZIp599lnHcY4fPy62bt0qlixZIk477TSxefPmmm3cmJmZEUQkZmZmgjQfhJRCoSCISBQKBe3nXsGyLEFEwrIsIcTrduD1vWAPvmbd89ArNgCgmwnSfwcSKGEBAqX74E4oFov1XEc0NjZmXy+LkWg0KohIZDKZnrOHLEj4eeg1GwDQrQTpvyNCCNEeX03zmJ2dpUQiQTMzM7Ro0aJONwc0iXg8bhfnKpfLnW5O21CH1vb39ztGq1iWRePj4x1sYfthmzAodQ9AdxCk/8ZkgSAU9HLlULnOx8TEhEOcRCKRnhMnAABA1GAlWQCaASqHkl3QsFQq2fWAIpEICSFqEme7Hdl7EovFiIh67nkAAFCwJNmwgByU7sGUENtribJ8vZFIxM5BEaI2cbbbQZIsAN1NkP4bHhTQUdwqhxYKhZ6pHFqtVimTyZAQgqLRKFWrVSoWizQ+Pm57VnrBg1AqlYiIakrdFwoFx/cAgO4HSbIAdJh8Pk+7d++mUqlkJ8RymMOyLNqwYYMtWrq9Fko2m6VoNKrNuxkZGaFqtUoTExPtbxgAoCkgSRaAeYQqTohOeQ0mJiZsj0GvJMqOjIzY+SayV61YLFKpVLI9KQCA7gchnnlEWMuAm9qVz+dpZGRE2y6ULX+dDRs21IRxuENmD0qvwOEcOSlWN8MxAKAHaHVCTCvo1STZsCaUms5vSvDsdHvDSi8Xq1OBLQDoTlBJtosJa1l4U7vUMu1haW9Y4Q45Fot1uikdB7YAoPuAQOlywvp2aWpXWNsbNthOfX19RjsVCgUxNjbW/sa1GTwzAHQnECg9QFjfLk3tCmt7w4LsWTLV/egV71NYvYQAgMaBQOlywvp2CQ9Kfagd8NjYmB0aU0WLZVld60GRr9uUz4RnB4D5DQRKFxPWt0vkoNSPPJuxEEJks1mH7XhmY/6czWY72NrWIT8zpvXdKs4A6BUgULoUjOLpDeQQD4sT/tvtdgurAAcANIcg/TcKtc0j3MrC8/edwNQurt+h1vHodHvDzujoKJVKJcfMxvyXC5Xl8/murCMjz+x88803U6VSQf0TAHoUlLoHIGTk83m64447aGpqqua7TCZDU1NTXd9px+NxqlQqFIvFqFwud7o5AIAmEaT/RiVZAELG7t27aWpqipLJpGN9MpmkqakpymQyXS1OisWiLU4qlUpPTJIIAKgFAkVDWEvKg+6Gn7sNGzZQJpOh6elpx/fT09OUTCbpE5/4RGca2Abksvblcrmm7D0AoHeAQNEQjUa1P4r84xmNRjvUsvYCodZe+LljD4qO6elpuuOOOyibzba3cW1AN+eObm4eAEBvgCRZDXKiHn/uxQnLuMMkopqZZdkWoHmoz50JDvN0G2FNAgcAdIiWjylqAe0aZowCYxj22Qm4Doq6JJNJ+y8AAMxHgvTfGMXjAUYTvO4x4aTFXvIidYq+vj7S/ddMJpM0PT2NewAAmJdgFE+TwGiCU4yOjto2iMVi6BhbzMjICAkhKBKJ1Hw3PT1NlmWFItyBHCUAQCuBQDEQttEEnewMINTaR7FYpFKpRJZl0dzcXE2uSSaToQ0bNoSi80cyOQCgpbQ43NQSWp2DEsaS8p1qE3JQ2odqW54qIJPJOP6qUwd0EjwfAIAgIAelQfL5PEWjUW0oo1gsUrVabeobbD6fp8nJSbIsq+ac/EY9PDxsv7Fy/kErRhZls1mKRqM0Pj5uHz+bzZJlWXbp9ZGREXt9X1+fXcpetlmxWKTx8XEaGRkhIqqxWSvs6IWf+0pETdnGdF1ubdi4cSMREe3atYtGRkZsTwrfi2q1Srt373asbzdy+/nfRGR7THgkTqlUsq9FpRP3HgAQDgL13y2XSy0gbJMFqrPRyhQKBc8ZWOXJ4eTj6Na3amQRX4M8wZ+6jn4/gqRQKIhCoSDS6bT9Zs//zmazNTMZm66r3W/ZfrxQzdqmkTYIIcTw8LDjHshYliWGh4d9PVvNQG6D3E4ebZTNZh2TGpqeZ911AgB6C8xm3GaaEX5Rf9TdfuRZnMRisZZcgyxS5HbIixp+UBfTNXS6g/ITkmjWNo20wbSt1/pWYGqveu/lGZflZyQs9x4A0HkgUDpAM2LxuvoX8vH4TbYVHhS5zZZliUQi4WhHJpOp6ZDcOii5fWGrJ6O2h70+um34mtzEg9/r0nkieF/2lri1t95nq1EPn+6csndMvef8bNTzvDajrQCA8AKB0gSC/FDytrof4yA/qqq3gj0kasiklW+kuo7Hz8IdeSwW03p4+vr6jF6fTnQ8chtNdpTDFn6O44V6Ht7XTQQ149mSz2sK1/Bnt+OpbTAtXFCORUojNvJaDwCYX0CgNIEgP5TyOj8dn9c5dW5yVZx4tbMRVFd9EHHi5kFRvUKtar8Xps5e5yFopgdF3kc9vmlkTrOfLdPz5Pd43IZIJOJLpPB56rERQkMAdB8QKE2inlwBtaOuR5yoXgxTsqS8b7M8EDqR5GdR81VUYVIoFGqSZk2iq5W43VP+N3e+LBrUbeTQRT2dqE6cuO0rh/7UZ6seD50qivy2Xd2fRYiXSKnHRvWIPwBA+IFAaSJ+fygbEShqRy6EqHGjt+MHWhVJXp4UXQclixD533IND3X7duHHKyZfs87T4yYo/HTAaievhvF0+8o2k5+LegSeGlbyKwBMHhg/wjWojdS2NjMZHADQWSBQmozXD2WjbvixsTFHoqYqitLpdMtzNPicqVTKdfSOvKRSqZpE2WQyab/xp1IpUSgU7G3S6bQQ4vUQUiQSaek1qXh5objdOpHC9shmsw15s8bGxoxhD92+qjDg/WSh4Bf1uVJFktd+3D5+VnlouZuADWKjepOIAQDzBwiUJuLHg9JoIqP8w8ydpJoLwcfi+hemttb7I67rHOLxuKdIyWazYnBwsKZjUj0F6iKHGYK22UsgmGzE4kA939jYmC2iVBvIbW3Ei6U+Izrh42c/1TsRNLzD52Vxobs29TlS7c3HSqfTxjDP4OBg4PuqijH1/0CYKugCAOoDAqVJ1JOD0ki8Xc3R0K1vdbIsH8dU38RrYbHilp/Ao2Lq7Xi8QjUmG5nOJ5eS123vx8vgt806MaBbr9tX9tAFudemZ1P3TPl9jnThO52ACop6j7zuKQBgfgGB0gT85CsI4XTZmzpEtx9V9Q1ZDa/IlVn5LbsRMeQFt4ffsIMMO2aXvp9RQHxcNZHSL142MH02jV5ptQdFiFrvmNxGk/dL3YbFUhCRYvLQyc+VSSiZvFU6j476LNRjs6AhMADA/AICpQn4DSPwD778tiiv98of8eqAdJ1jO37EdSEfP4ubOFGHprK3hetlBCWVStXYgNttWZYtstQ8Bl0oTr5OnQBotocqaOGyoKEhEyaRxPeN84TU9qrt1BUVVAVtI3kjSJAFoDuBQGkDXmGZIG+4Jhe+KYlR7VT8jARpxrU2snChNnVRwypB0IVg5LZalmUshmbqAN28E82yb9DO1683zy/qfl4F6UziSFdJWP6+XlsFFXEAgPkDBEqL0YVldJ1vkB9WkwjQ/UjLSZ1qLY1mj3bQhTqatfCIn3rbqxODunwdU90P1bbskWExJdu8WRP01dP5NqsGjs4rJo+ocmuPur0aotPVjqnn3rYyfAkA6DwQKC1GF5ZRO+9632rVY+nc++pEfby9mkfRrOs0ibD+/v6mCJVG3rJVUcJtNRVDM+WgqMJGd/xGR5F0uvM1eU5kceHWHtP26vNYr52a7SkCAIQPCJQ2YArLNOo9kTtU+Rwc81cLnulmkG0Wcr6CTqDIdTAaESuNhiiEEI7jqcKNQymmDlTuaOXkYFWgNeI9CUvny+fjIeSq54Ntoea28H68vVrKnj138v5BvT7tqpYMAOgcEChtQheWMVUidUMWAuqoIDnxUxUhqmiIRqPGpEk+TpBOQN52eHhYWJZVU8wsm816ljx3s1EymQzU8ciFwsbGxkQqldKeXxd6YPGiq4OiJtCqQqxeIcHH1Nm9UCjYdjWN4GlFp6zmjuiqw8bjcUc75O9NtuXryGazDqEn06pQJABgfgCB0ibUzkz3Q+/VoQV5szaVkffySOhCUo28yatJnvUm0dYTEtBdC5FzRJB6T4KGaHS5LfV6Obzs3eq6Nqb2qNenPk+cvGwKL/KiCw/xPur9VUNBCNkA0HtAoDQR9c3Xq7KnPOyY6FS5d7djm1zhpiRDt/LisidB9QjIw0fVTl4deuoG78uJpPUWdJPFw/DwsOd5dW1Qz53JZLReJTchwPfBJAT9Ck0/7dXlnujq6Mjixc3L4HcovLx9Npv1rG3DXq1sNmtPVyCjs7tqI/UesZDRbYvQDgC9AwRKE1E7F+7MWQxwLF+eb6ZQeL3QmVudinq8GTphlMlk7PMPDg4aQy5yW3RegiC2UOtgpNPpmo6PbSPPz8OdVaOVQdWcCDexxnP+mDo7WRDIb/lyKIoFnnyMIB0rX786ekeulyN/b8oF0bVbbQMfM5FIaIWPlziRz6+2wa3+iXrNpvP5fd7bnZ8DAGg9EChNxhRW4B9z0xuln5CC29u12/ZenbLaeaidg3wcP/U4TO1Ur9nt3ETmJOB6UGucuJ3X6xym0u2yADJVm/XTsZrsLZ9Xrkfit91u90W+Dl0Yx+t58arxo7OR2l713gSttQJxAkB3AYHSZMbGxmomV9P9OMuf68mrkN+edQQpO6/rdPiNWh515He2WJ23wO1tOpvN2m/ebDs1j4E7PbfkXTmBVWczr9oshULBd84D28dN7Kht8dux6jxWajhQXdh+Xp4anXfGFAYL8rzw/ixkdMX2ZPur3h4+Bv+f4L/sZdRdi3xMiBMAug8IlCajdsSRSMTVkyFX1PSKn3Pno3oDVJe5ziOgG94cZFEFg1rm3A+qHdQ3ZL9eBjUvg3NzuG3xeFwkk0nHUGC3zp07V/6ek2i9Oj1dyEi1s0mkmIqvmTxwvJjyiqLRaI2Q0R3Xsixt1WFTGMzvqCtZ3MhCRK3gK69ndLVR1GO6iTiUuAegO4FAaTK6ToU7PK83UL8uevnHXv0R5234nHJ4JEh1V7Vj0nWYQd9adbapNwFS7nB1tjTZ2O91e835o7sW7tzluWp0djKVr9cJtKDCUhZqajVcnVjwOlfQYeF8DtmDIgvkWCzmOopHFaE6kaL7fwAPCgDdBwRKE5FHWfhd6slBMQkGdRRKJpNxdJJ+28ZtMoUx+NxBypPLbW2kkq5bCXaiUyOhdMOH5Y7W5IXgTpUnbTS1S8270Ak/U6jILTShhqhUb4vXIodNTNVxdR29W86I6frcxAkfXw1LqWElOVynqwEjf1Zr6piuAwDQPUCgNBG54/ITz3cbTqmi60zcOi41F6KenBSdqFHfyv10CnLnp+4fVKSo52UbmEbomISDaiOdANO1S1efw9S5u4VZdB267h7rvAZu90tGJyy88l1UG9XzzOjs5fe5CZKX42c/AMD8BQKlicgeFK98B1WkBE08lV3mqhteHU2iG+brpyOXq3zK+/Lx3Ia1ynjlRbDHwi/yfkS1k9jp7MCfeZI/0/3h3Bq3miNsb1lImIqSmd7y3cSKqbN1yz+R74ecqC23R+f54nPxMG++R+p0Cclk0hG2MYV+5DbL16gbRq0TE7K3RCfOdJMzyvuiDgoA3QMESgvw8lZwZ8CLXCjNT9jEr+tfThpNpVJ2Mqmft3E/i1thOaaeAnO8n9tbthp+8psrodaeUZfBwUGHMFPPI4fk0um0SCQSNfVA5Dlo5Dooqh3UcI/XSBw3Yck5M2PS7NWqWJJtxMfnc3EZfdXOLNRM51a9cyw2uagee+GGh4ft9arAZUElhyN14TuEdADoLSBQmkyQzl9OYNXlCLgdP6jQUF3sQd34uu3rqd3itd7vfo0sumvReaLcEm5NdULU+yLbSHdNssh0u+/y+UxJ13K71ErBOnHiF7ndsu3kMJfcJlnEyR4i+d/yMdVwJKOOBgry/AAA5j8QKE3GVO/DtKg/0H7FiRD+k3K5c9JV/gwyskdeBgcHfdvEFN7w6lxM+/kpwa4TJaaOXZdIKoc2TPZUj8ceEvW+yp4TN4Ep20OXDCyfUz4XkTPB10t8BunU1XswPDxsTDiWZ6lWbakmzLoJbPX/hMk2upAOwjwAdA8QKE1G/iGWf7zVH2NdB2uqLcI/ujrXv5dIUTtRtZKnl0dCJ2Bkb4Ff1LCU3311+8mdZlBBKHeisn1kkcIhiaAiSM074fa75VTwOd1E3NjYmF3bRXeswcFBkUgktEN85SUWiwXuwE3hpno8Weq1qUUAdcfU5eTU65UDAMwvIFCaiO7tWe585E4sk8k4fqBNFTH9hkJk4eBHbKg//EE6Y12n4QdT/Y8g++nOW68XiI+jFr6Tr8/v6CC5o3W7T6oolIvVeXXEfmwu28rPKJ5GCFKjRbWLrkJxoVBwtFlXSK4R2wAA5hcQKE1EftuUkw7l0IQQtTO88iLH7tURQaa3Xk6+9BIYLF7kt3xur9ebt5tICVoHpVEPippo6nXdbgJDFgt87WxrOdnUr0gxXRs/C6rokQu6ydcbpPKsm63kxW8Y0S+q3YLYRRfacgv3NMM2AID5BwRKi9G92bl5PVQhwZ/dRswEdbfLeQB+xYkaGpEFV1Ab+H3b9dpPlzMSVGDxdagduC7Z1Ot4pmuThaY8yZ9f0eDH8ySfVy3vz981Q6Sow6/95kDp5hKS7e5Wt0cX1uR1qm2QgwJA9wCB0mLUGL4sJrhT9dO5uo2YqScxV26HKj5MnXImkxGFQsGRdOtFvfkCXvupHZq6zmvRFVozjcwh8jddgVvbTYnJuvwT3fW6eQlM4SNTMbmgdWdkdKFLP8+vPNcRD/XW7S8PQzaJFPV+yZNYNiK+AADhIkj/3U8gMPl83vG5Wq1SNpsly7JodHSUisUi5XI5ikQiJITQHiOdTtvHUo9XLBZJCEHZbJaeeeYZmpqaMrbFsizKZrOUy+UoFosREVE2m6XHHnuMTpw4QX/3d39HExMTVCqVtPt/6lOfIiKi6elpSiaTlEwmtdsVi0WqVquUz+epWq1SoVCg0dFRxzb8uVqtao/htd/4+LhtR7apbE8vpqamKJPJOI6fy+XIsiz7+qenpymRSNCSJUtc7UpEtHfvXu21bdy4kYjIcVz5mufm5oy24GthO8jXJrdbtlU+n6dCoWBfTzqdplKpRJZlEdGpZ4mvRb5P8r+JTj1r0Wi0xv4bNmygqakpKpVKdODAASoUCjQxMeFqn2QySeeccw5t2LDBcZ187FwuR8lkki688EIiIpqYmHBcc6lUctimWq1SJpOxr2t8fJxGRkaoVCpRJpMxPlMAgC6m5XKpBXTag+IHr2RD03w99SS5ykmhupCBn3CRW5Jsp5MVvdqvm6fHtC/PEKw7js7epvsj281kT9N1NGJf9XymarVuYUjT+f3m5+imcTCF7uSRVG6o0w2oE2f6qc8DAAg/CPF0AHliNL/JrXJdDiGcbm4hhEilUiKRSLgmzMpl6mW3uK7aqbqvnNjJ5zcNn21UnHhVkTUNuRaiNtzFVXu5I2ab83o1t0cd+ZLNZmtK/svXq1ZY1SVG8z1UKwhzbob8PASxgR8byuJXHVGm5uHwsbkCrElIpFIpUSg4R9yYRlIlk0mRTqfF8PBwzTXI9pJzc/ge6a6R28fPuLyf+jwDAOY3ECgdQH0L9TM8WM4TkefvkfdXcw1Mi5pkqnaqanv43Op55fM1cySFH++B/G+5cJeu89XVl1E7ZiFqS8nL15nNZu2OWXcsuSS+PFzZJBY5pyWZTNbYUydY6rWhfG90z5V8rSzudM+TKnS8njHTMyejHofbI88LJNtBFki6/eE5AaC7gEDpEKq40I2S0XVqLBIikUhNoqgupKATLLrEUO5A1ARY7ki5fTo3er31Tdwwvb27JUuqnaEqWNzOYbJl0Cq/cmfrJRblxFvdORsReyaxplt0Hb1sG7Ucv3wsU6hLTXw1oRYO1B1Pd041LGSqIwQAmL9AoHQIv2XqdYsa9+fj8HoeJcGonhH1x1wNN6nbqSNYdB4UXRXVRvHjnVHPr3qDZK+E2znUa1MFnxwCMR3LdD/j8bjnKCDu0E2hCq5M7MerovM0+a3lIttPNzrMT6l63SLfO7X+jto2dYJGWSDpyuZjFA8A3UnLBMott9wi1q1bJ97whjeIM888U3zgAx8Q//u//+vYZm5uToyNjYkVK1aIwcFBMTw8LPbv3+/Y5sSJE2Lr1q3ijDPOEKeffrq4/PLLxaFDh3y3I6wChQlSjdMkVuTjyJVJZbhjdfN2yMXl1OPJ51NnpVU7dL/1UYLYx807o1aCDRpu4howfA41v0EWJ15CSRUpqqcryMIiJehEf2r+iiwA1DwYeRkcHNQKVbaNmjciC5RIJFKTgMz7qDNWq94QIZy5PyYxJYdEWfCp3jLkoADQPbRMoFx66aXi9ttvF/v37xePP/64eP/73y/OOecc8fLLL9vbbN++XSxcuFDcddddYt++feLKK68UK1asELOzs/Y2V111lTjrrLPEzp07xd69e8XGjRvFmjVrxMmTJ5t+ge1GdVPXI07kH26vjtlvvoi6nfqmq5v1V96vWW+xQTwoOpHSyDnk0IG8nVeoyORVCFqVVhYNjdg0qDjS5UPp5kGSj6s+J/LiZi8vm7nZUX7udPcBADD/aVuI5+jRo4KIxOTkpBDilPdkaGhIbN++3d7mxIkTIpFIiG9961tCCCGmp6fFwMCA2LFjh73N888/L/r6+sQDDzzg67xhFSjqD73fhFl5kWeu1YU2dOdzy+nQrVcTadX2ZTIZx348CqjRt1i3EUJyIqmurX7zEUw2MY0QMR1Pl6SrEyJ+q93qqvrW4xng9qTT6Ya9OKr9U6mU1va8j+xdU+2mlv6X9wvSLvk65URaeFAA6A7aJlCefvppQURi3759QgghfvOb3wgiEnv37nVsd8UVV4hPfOITQgghxsfHBRGJ3/3ud45tLrjgApHL5bTnOXHihJiZmbGXQ4cOhU6gqB2hn0qobjkMauy9XjHi1WGb3nbVJMpm2UftIOX1sjCTh53q/pqGq+raqwoy1ZPip81BxEiQJYht/Xh1vBYe1eT2POiuXbdelxNlqq7rZTtd7Rp4TQDoPtpSSVYIQddddx1dfPHFtHr1aiIiOnLkCBERLV++3LHt8uXL6ZlnnrG3icVitHjx4ppteH+Vbdu20U033VRvU9sCV/7kCqj8l4ioVCpRf38/nTx50rHPiRMnao4Tj8epXC4TEdnHI6qt0uq3mqu6nfyZK43u3r3bcYxIJEKVSsVug3qOeuDzclXbqakpmpqaqqmGytVEM5mM/f34+LjdViIyVsXV2YSrllqWRRs2bLCPE41GqVqt0sjICI2Pj2uPx+fhNsrtagZcedgv6vWVSiWamJgIdM6DBw86jiFX8VWfE67qy5/l7dVKsHIFWSKy7Ut06hm67bbbiIhocHBQ+9xz1V610i4AoIepVwV94QtfEKlUypHc+p//+Z+CiMQLL7zg2PYv//IvxaWXXiqEEOIHP/iBNpfgkksuEZ/73Oe055oPHhQTcoKiWpNDt2SzWZHJZFwnEmxGm1Q3Ps/Jo7anFQmKav6L7Dkher0OiumtPkib5Gs1hY+8wjz8l0eiqKEeddi21+geeWnUSxAkfCifU5fo2ihyCEgOaXH4SB7urmsXZjAGoPtpeYhn69atYtWqVeLAgQOO9a0K8aiENQdFh6lTVBfVBd7KH2lukzqxodoG7khaUSxLTSI25YT4TQL2wm9IzG1fvxPouXXCqm0buaZ6clBa9ZzJ4lZOanYLkxUKBe0oIQBA99IygTI3NyeuvvpqsXLlSvGrX/1K+/3Q0JD4+7//e3tduVzWJsn+8Ic/tLd54YUXuiJJVofbzMemzoNrnnglCTZSOp3bkUwmazoKOf9EzVloBiYb9PX1ac/jNdzai7GxMZFKpbRCq1AoaMu2+22zbCfOnWFbenlSBgcH65qF2DRs2M/SDGFkalOh8HodFLn2C1Ft3Rj53GpBQ3hQAOheWiZQPv/5z4tEIiEmJibE4cOH7eXVV1+1t9m+fbtIJBLi7rvvFvv27RMf+9jHtMOMV61aJR566CGxd+9eYVnWvB9mbBIL8hwkfhMb5cnY3N7w6/UK6BJUdd4MolMFtlSx0wxh5Pb2z23TFb7z6rx0bZOvU67nYlqvO5bXvVPDU7rt1VBQPB53vRbT9bFoVAWtfN+8hIts40ZRnydVpKTTabvN0WjUIRT5Gvr7++05fiBSAOheWiZQTD92t99+u70NF2obGhoS8XhcvOc977FH+TDHjx8XW7duFUuWLBGnnXaa2Lx5s3j22Wd9tyOMAsVrBEnQESBqaXK/5w26j5xPYWqjXwHkdW61A1M9DarHQTdLcVB7MGpowTRKxU971UUXCtMN3dZdY9COWG23aai4n+erWUJAN7JHLVaoE5pq/RP13kCkANB9oNR9hzCJBfnH2a3qp7wEybmoJ0/DjzdHnpnX77W6nVsOf6hDh1Xvgq5D1dVJcbs23obre5gEhm7iQfVYXgIzk8nUTIDH9uNtvDxTflHvnW44Lyf0ulU1bqYAkGvc6ETU2O9n1XYTS6p3C7VPAOg+IFA6iEksuM2Boi5BK6cKEXxyPy+Bwm/kfjpvv8KIt0+n046cEK9kT91oHq/Oi88ljyaxLEtb4dcrCVhnK1WwyHbyyjtSw0n1dMa6NqlhMZ1YUCfy07W33rbpvFKyWNS1Wdeeem0CAAg/ECgdxiQWgkxvH2Qm13qFgpq3UM+bdqPCSM1XaObbvjohnUmI1dNmXWdrEjpu4aRGwhmqzdwEgamAmltIJWjb5PPJz4N8HD9hRIR4AOheIFCaALukTbkJXqEPVSyob/RqoqNaW4PP7fVDXU+oxStJVu2ITW+y9YSWhKj1JvnJn6g3V8PPxI1ex1bbq3oo+Hudt0m2sZcwCOI1MAlc+ZmVn2E+lzy6Rn6G63mOTHbSPQ+FQsG1DhBPr1CPtwwAMH+AQGkCusQ/t/Xyd6YcFF6vDhFV38hbPYpH17agnXcjHZqXMGpUpKhtMV2jvN7vdapl803bqdfJ6011SILYT223m4dGd2yv56aemjNe55Db7LfsPTwpAHQfEChNQu1ggogTRtehjY2NOYqj8bpCoeDYvlV1UOS2qp4ctRNx8wrUGxLwEiim0Ty6ocB+2jY2Nqb10liWpU3Q9DqWaQSManN1ckRG9pYFsZtqO5MY0g2l9nuvgobs/J6DnzM/xeXkfVtRyRgA0DnaMhdPLyDPL8JzjBDp56cxzY2zYcMGx18ionw+T0REu3fvttfzOnmOHHmdDv7ere065LaOj49TJBKx55fhOVR4XpxzzjnHdX/dOeU5WlR4rhXLsujAgQN08ODBmm1OnDhByWSSpqenHXPyyDb0c21MPp+nr3/9647teM4fy7Iccx65HSufz1M0Gq2ZG4ivS75nRETDw8M18+0Ui0USQlAkEiEhBPX39xvtabq+VCpFb3zjGx3b879vu+02EkK42kPeXr2GSqVCsViMKpUKFYtF323yOseWLVsoGo3a8xsVCgUiIsf/K4ZtYlkWlUolmpub82wDAKALabVaagXtTpKV8xi6rRS37o3czVPUjHP5LdHeSD6EjOqt4uPJQ56DtL9RzxFv53dW5Wa3w88xWxFe0R1TTfRl75JpdA8AYH6DEE8T0YUjuukH0xSG4Ov2E1bxi9/kXFlMyO1ppGaI7ni83qvMvS7ZVM2t8LKTSQDISav1XFczBEUrBI8ONSTpZwRXN/1fAwBAoDSNIDko85Vm1cAIek55RIc6gqmZNm70+tRy+/JzILfbS6DoyuarIifo9TaS1Gpqm+4crXgGZG+aEOZE5m75fwYAOAUEShPwk4yIH8/6kG2oc+nL4ZdO21gNB3Gb1Pb6bWezvRX1JLV2GpP3p56pDQAA8wskyTaBarVK2Wy2JsmR/10qlVyTQYEZtm1fXx+VSiU7YdSyLMpms3TbbbfZibGdtrGcKM0Ju2pip/qMuNFIgrFKvUmtnUa1gZwQS/R6ojYnMXf6GQAAdIjW66XmE/ZKssAbNWFWV6CLQvT2bMqb6dRbfjuSWoMQNExkmimaQ2hycbywPAMAgMZBiAeEGrkzdcvNaFX+Q73ocmV0ibOtpl1Jra1sk7xeN9Gg/O9mJmoDADoLQjwg1PgNc4QpXDEyMuKoL8JhqVwuR4VCwVhLpdnk83manJw01k3JZrMdCYnIoTD+zDVv3O51LpejbDbrqIuibo8QDwA9SsvlUguABwW0E3WECX9WE2fbQRi9J7p2BJ24stGRSACA+QFCPD1CvcNDOzGstJ008/o4/MCl8tVwFK9vZxgibPknDNtdN7JItbt8j9Ttu+EZBADoCdJ/97XPVwOaTTQapVwuR8Vi0bGeXevRaLSp+80XWnF9F154oTZUweuHh4cbanMQRkdHqVAoUC6Xo3g8bgyjtBu2uzqySGd33nZkZMSx/cjISFc8gwCAJtAGwdR04EF5nXrfpsP6Ft4smnl9YbVV2Gqg6EbjkEsITJ1I0zRTNACge0CIp8eoN47f7fH/Zl5f2GwV1vbIwkSew8qUM8OihLdFcTYAupsg/XdECGlowjxhdnaWEokEzczM0KJFizrdnFAQj8dtV3m5XG75fvOFZl5fWGyljo5xGy3TLnimZz6/bKv/9//+X81Mz/L2ql11M0MDALqDQP13y+VSC4AHxQk8KHq60YMS9lE8clv82CosdgUAtAeEeHoI5KDo6dYclLCPwApiqzDZFQDQHiBQeoR636bnw1t4I8j5Dab1fjvybrdVMwliK9gVgN4ElWR7hHonnmvmhHVhRJ58Tp5Ab3R0lCYmJqhUKlE2m/V9rG62VTMJYivYFQDgBZJkQahQky1lgiZPhjGZFAAAepkg/Tc8KCBUcAEvIudcPLK48Is838vNN99MlUoF4gQAAOYJqCQLQgWHZ+RKsCxOLMsK7PofHR21q5TGYjGIk5CQz+drKv0yxWIRQ4wBABAoIFxEo1EqlUq2SOFS7pxTErQEerFYrCm9DjpPt0+3AABoAi1P2W0BGMXT3fBIjmg06vgbdGQHhrGGG9wfAHoPDDMG8x4uec5L0PlZMIx1foBCbQD0FpjNGMxrisWiI5zDYZ8g4Rm3YayFQgHDWEMCcoQAACYwigeECjkhtlQq2Z0X56QQka9OzC3JEp1geNDlCOH+AACIkCQLQoZcZK1QKFC5XKZCoWAnzsLz0T3IQ8f5PusSZwEAvQk8KCBUcDhHDs/I9Uz8VoAF4UZXNE++z/JnAEBvAoGi0MxKpiA4KIHeG+A+AwC8QKl7BVM5dJRJBwAAABoDpe4bQOdmhjgBAAAA2gs8KAZYlPDoAogTAAAAoDGC9N8QKC7E43F7CGS5XG7ZeQAAAIBeIEj/jWHGBjCHCwAAANA5IFA0oD4DAAAA0FmQJKuA+gwAAABA54FAUUB9BgAAAKDzIEkWAAAAAG0BSbIAAAAAmNdAoNCp8vamBNhisYjS9gAAAECbgUChUxPU6UbpcMJsNBrtUMsAAACA3gRJsoTy9gAAAEDYQJKsBMrbAwAAAK0Dpe4bAOXtAQAAgNaAUTx1gvL2AAAAQDhADsrv4fBONpsly7KIqLZybLFYpGq1ilE9AAAAQIuBQCFneftSqWT/m+fgYVjAAAAAAKC1IMRDzvL2qvdEFi1EZH8PAAAAgNaBJFmJfD5v1zxhQcL5KERE2WyWdu3a1bTzAQAAAL0EkmTrhAu2EZ3ynBCRLU6I4D0BAAAA2gUEikS1WiXLsiiXy9HExITju0wmg5mMAQAAgDYBgSIRjUapVCpRJpOhUqnk+G5qaop2797doZYBAAAAvQUEigQnyU5NTdnr5Hl4SqUSaqMAAAAAbQACRWFubs7xmcM+nJOielYAAAAA0HwgUAyw54TDPkSnEmeHh4c72SwAAACgJ4BAkSgWizQxMUGWZVG1WqVYLOZInCUiVJEFAAAA2gAEikS1WqV0Ok2lUokKhQKVy2W7UJtlWVQqlSBQAAAAgDaAUve/J5/P0+7du+ngwYOO9aOjozQxMYHcEwAAAKCNQKD8HnmI8dTUlGMOHlmcoFgbAAAA0HpQ6l6CJw3kcI4Kz9cDAAAAgOAE6b/hQZFg8ZHL5SgajToqx0KcAAAAAO0DSbIKo6Oj9ugdAAAAAHSGwALl4Ycfpssvv5xWrlxJkUiEfvSjHzm+/+QnP0mRSMSxvPvd73ZsUy6X6ZprrqGlS5fSggUL6IorrqDnnnuuoQtpFsVi0TFBoDy7MarIAgAAAO0hsEB55ZVXaM2aNfSNb3zDuM373vc+Onz4sL3cf//9ju+vvfZauueee2jHjh30yCOP0Msvv0ybN2/uuNeCc1AYrofCibEQKQAAAEB7CCxQLrvsMrr55pvpwx/+sHGbeDxOQ0ND9rJkyRL7u5mZGfrud79L//iP/0iXXHIJveMd76A777yT9u3bRw899FB9V9EEWJyk02kiOpVzMj4+7qiDQoRS9wAAAEA7aEmS7MTEBC1btoySySQNDw/TV77yFVq2bBkREe3Zs4dee+012rRpk739ypUrafXq1fToo4/SpZdeWnO8crlM5XLZ/jw7O9v0NlerVSoUClStVikajdoJsfy3Wq1SNpvtuJcHAAAA6AWaLlAuu+wy+shHPkKpVIqmpqbsGYL37NlD8Xicjhw5QrFYjBYvXuzYb/ny5XTkyBHtMbdt20Y33XRTs5vqwK1CLEbvAAAAAO2l6QLlyiuvtP+9evVqWrduHaVSKbrvvvtcw0JCCIpEItrvbrjhBrruuuvsz7Ozs3T22Wc3r9EAAAAACBUtH2a8YsUKSqVS9PTTTxMR0dDQEFUqFXrppZcc2x09epSWL1+uPUY8HqdFixY5FgAAAAB0Ly0XKC+++CIdOnSIVqxYQUREa9eupYGBAdq5c6e9zeHDh2n//v100UUXtbo5AAAAAJgHBA7xvPzyy/TrX//a/jw1NUWPP/44LVmyhJYsWUL5fJ7+5E/+hFasWEEHDx6kG2+8kZYuXUof+tCHiIgokUjQZz7zGbr++uvpjDPOoCVLltCXvvQlOv/88+mSSy5p3pUBAAAAYN4SWKD84he/oI0bN9qfOTdky5YtdOutt9K+ffvojjvuoOnpaVqxYgVt3LiRfvjDH9LChQvtfb72ta9Rf38/ffSjH6Xjx4/TyMgIfe9737OLogEAAACgt8FkgQAAAABoC0H6b8zFAwAAAIDQAYECAAAAgNABgQIAAACA0AGBAgAAAIDQ0ZK5eFoN5/W2Yk4eAAAAALQG7rf9jM+ZlwLl2LFjREQodw8AAADMQ44dO0aJRMJ1m3k5zHhubo5eeOEFWrhwoXH+nnrgOX4OHTqE4csewFbBgL38A1v5B7YKBuzln1bZSghBx44do5UrV1Jfn3uWybz0oPT19dGqVatadnzM9+Mf2CoYsJd/YCv/wFbBgL380wpbeXlOGCTJAgAAACB0QKAAAAAAIHRAoEjE43EaGxujeDze6aaEHtgqGLCXf2Ar/8BWwYC9/BMGW83LJFkAAAAAdDfwoAAAAAAgdECgAAAAACB0QKAAAAAAIHRAoAAAAAAgdECg/J5vfvOblMlkaHBwkNauXUu7d+/udJM6wsMPP0yXX345rVy5kiKRCP3oRz9yfC+EoHw+TytXrqTTTjuNstksPfnkk45tyuUyXXPNNbR06VJasGABXXHFFfTcc8+18Spaz7Zt2+id73wnLVy4kJYtW0Yf/OAH6amnnnJsA1u9zq233koXXHCBXfRp/fr19OMf/9j+HrYys23bNopEInTttdfa62CvU+TzeYpEIo5laGjI/h52quX555+nj3/843TGGWfQ6aefThdeeCHt2bPH/j5UNhNA7NixQwwMDIhvf/vb4pe//KX44he/KBYsWCCeeeaZTjet7dx///3i7/7u78Rdd90liEjcc889ju+3b98uFi5cKO666y6xb98+ceWVV4oVK1aI2dlZe5urrrpKnHXWWWLnzp1i7969YuPGjWLNmjXi5MmTbb6a1nHppZeK22+/Xezfv188/vjj4v3vf78455xzxMsvv2xvA1u9zr333ivuu+8+8dRTT4mnnnpK3HjjjWJgYEDs379fCAFbmfjZz34m0um0uOCCC8QXv/hFez3sdYqxsTHx9re/XRw+fNhejh49an8POzn53e9+J1KplPjkJz8p/vu//1tMTU2Jhx56SPz617+2twmTzSBQhBB/9Ed/JK666irHure+9a3iy1/+codaFA5UgTI3NyeGhobE9u3b7XUnTpwQiURCfOtb3xJCCDE9PS0GBgbEjh077G2ef/550dfXJx544IG2tb3dHD16VBCRmJycFELAVn5YvHix+M53vgNbGTh27Jg477zzxM6dO8Xw8LAtUGCv1xkbGxNr1qzRfgc71fK3f/u34uKLLzZ+Hzab9XyIp1Kp0J49e2jTpk2O9Zs2baJHH320Q60KJ1NTU3TkyBGHreLxOA0PD9u22rNnD7322muObVauXEmrV6/uanvOzMwQEdGSJUuICLZyo1qt0o4dO+iVV16h9evXw1YGrr76anr/+99Pl1xyiWM97OXk6aefppUrV1Imk6E//dM/pQMHDhAR7KTj3nvvpXXr1tFHPvIRWrZsGb3jHe+gb3/72/b3YbNZzwuU3/72t1StVmn58uWO9cuXL6cjR450qFXhhO3hZqsjR45QLBajxYsXG7fpNoQQdN1119HFF19Mq1evJiLYSse+ffvoDW94A8Xjcbrqqqvonnvuobe97W2wlYYdO3bQ3r17adu2bTXfwV6v8653vYvuuOMO+slPfkLf/va36ciRI3TRRRfRiy++CDtpOHDgAN1666103nnn0U9+8hO66qqr6K//+q/pjjvuIKLwPVvzcjbjVhCJRByfhRA168Ap6rFVN9tz69at9MQTT9AjjzxS8x1s9Tpvectb6PHHH6fp6Wm66667aMuWLTQ5OWl/D1ud4tChQ/TFL36RHnzwQRocHDRuB3sRXXbZZfa/zz//fFq/fj298Y1vpO9///v07ne/m4hgJ5m5uTlat24d3XLLLURE9I53vIOefPJJuvXWW+kTn/iEvV1YbNbzHpSlS5dSNBqtUX5Hjx6tUZG9DmfHu9lqaGiIKpUKvfTSS8ZtuolrrrmG7r33Xtq1axetWrXKXg9b1RKLxehNb3oTrVu3jrZt20Zr1qyhr3/967CVwp49e+jo0aO0du1a6u/vp/7+fpqcnKR/+qd/ov7+fvt6Ya9aFixYQOeffz49/fTTeK40rFixgt72trc51v3BH/wBPfvss0QUvt+tnhcosViM1q5dSzt37nSs37lzJ1100UUdalU4yWQyNDQ05LBVpVKhyclJ21Zr166lgYEBxzaHDx+m/fv3d5U9hRC0detWuvvuu6lUKlEmk3F8D1t5I4SgcrkMWymMjIzQvn376PHHH7eXdevW0Z//+Z/T448/Tueeey7sZaBcLtP//M//0IoVK/BcafjjP/7jmnIIv/rVryiVShFRCH+3mppyO0/hYcbf/e53xS9/+Utx7bXXigULFoiDBw92umlt59ixY+Kxxx4Tjz32mCAi8dWvflU89thj9pDr7du3i0QiIe6++26xb98+8bGPfUw7BG3VqlXioYceEnv37hWWZXXdsL3Pf/7zIpFIiImJCccQx1dffdXeBrZ6nRtuuEE8/PDDYmpqSjzxxBPixhtvFH19feLBBx8UQsBWXsijeISAvZjrr79eTExMiAMHDoif/vSnYvPmzWLhwoX2bzfs5ORnP/uZ6O/vF1/5ylfE008/LX7wgx+I008/Xdx55532NmGyGQTK7/nnf/5nkUqlRCwWE3/4h39oDxftNXbt2iWIqGbZsmWLEOLUMLSxsTExNDQk4vG4eM973iP27dvnOMbx48fF1q1bxZIlS8Rpp50mNm/eLJ599tkOXE3r0NmIiMTtt99ubwNbvc6nP/1p+//XmWeeKUZGRmxxIgRs5YUqUGCvU3CNjoGBAbFy5Urx4Q9/WDz55JP297BTLf/+7/8uVq9eLeLxuHjrW98q/uVf/sXxfZhsFhFCiOb6ZAAAAAAAGqPnc1AAAAAAED4gUAAAAAAQOiBQAAAAABA6IFAAAAAAEDogUAAAAAAQOiBQAAAAABA6IFAAAAAAEDogUAAAAAAQOiBQAAAAABA6IFAAAAAAEDogUAAAAAAQOiBQAAAAABA6/j8D+EPSL84oiAAAAABJRU5ErkJggg==\",\n      \"text/plain\": [\n       \"<Figure size 640x480 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {},\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"shocked_range = (300, 400)\\n\",\n    \"shock_time = int(end_time / 2)\\n\",\n    \"\\n\",\n    \"supply_schedule = [ {'from':0, 'to':shock_time, 'ranges':[chart1_range], 'stepmode':'fixed'},\\n\",\n    \"              {'from':shock_time, 'to':end_time, 'ranges':[shocked_range], 'stepmode':'fixed'},\\n\",\n    \"            ]\\n\",\n    \"demand_schedule = supply_schedule\\n\",\n    \"\\n\",\n    \"sellers_spec = [('ZIP', 10), ('ZIC', 10), ('SHVR', 10), ('GVWY', 10)]\\n\",\n    \"buyers_spec = sellers_spec\\n\",\n    \"traders_spec = {'sellers':sellers_spec, 'buyers':buyers_spec}\\n\",\n    \"\\n\",\n    \"order_interval = 10\\n\",\n    \"order_sched = {'sup': supply_schedule, 'dem': demand_schedule,\\n\",\n    \"               'interval': order_interval, 'timemode': 'drip-poisson'}\\n\",\n    \"\\n\",\n    \"n_sessions = 1\\n\",\n    \"\\n\",\n    \"x = np.empty(0)\\n\",\n    \"y = np.empty(0)\\n\",\n    \"\\n\",\n    \"for sess in range(n_sessions):\\n\",\n    \"    trial_id = 'smith_chart_' + str(sess)\\n\",\n    \"\\n\",\n    \"    market_session(trial_id, start_time, end_time, traders_spec, order_sched, dump_flags, verbose)\\n\",\n    \"\\n\",\n    \"    prices_fname = trial_id + '_tape.csv'\\n\",\n    \"    with open(prices_fname, newline='') as csvfile:\\n\",\n    \"        reader = csv.reader(csvfile)\\n\",\n    \"        for row in reader:\\n\",\n    \"            time = float(row[1])\\n\",\n    \"            price = float(row[2])\\n\",\n    \"            x = np.append(x,time)\\n\",\n    \"            y = np.append(y,price)\\n\",\n    \"\\n\",\n    \"plt.plot(x, y, 'x', color='black');\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"pycharm\": {\n     \"name\": \"#%% md\\n\"\n    }\n   },\n   \"source\": [\n    \"That's it for now: this notebook has shown you how to set up BSE to run market sessions like Vernon Smith's first experiment in his landmark 1962 JPE paper, and then has shown you how to alter and extend the setup to take it closer to real-world market scenarios: a heterogeneous mix of trader-types; supply/demand assignments arriving randomly; and the supply and demand schedules altering during the session.\\n\",\n    \"\\n\",\n    \"## Further Reading\\n\",\n    \"\\n\",\n    \"Here are links to some recent research papers that use BSE...\\n\",\n    \"\\n\",\n    \"https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4153519 \\n\",\n    \"\\n\",\n    \"https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4154426 \\n\",\n    \"\\n\",\n    \"https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4070885\\n\",\n    \"\\n\",\n    \"https://arxiv.org/abs/2012.08840\\n\",\n    \"\\n\",\n    \"https://arxiv.org/abs/2012.00821\\n\",\n    \"\\n\",\n    \"https://arxiv.org/abs/2011.14346\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"Python 3 (ipykernel)\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.11.5\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 4\n}\n"
  },
  {
    "path": "LICENSE.md",
    "content": "\n\nCopyright (c) 2012 Dave Cliff\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n(copied from http://opensource.org/licenses/mit-license.php)\n\nLast update: Dave Cliff, October 25th 2012. "
  },
  {
    "path": "Offsets_BTC_USD/empty_file",
    "content": "\n"
  },
  {
    "path": "README.md",
    "content": "<i>NB: in Q3 of 2025, 13 years after BSE was first launched, we'll be making BSE2 available in a separate repo. BSE2 is a major refactoring and extension of the original BSE. This, the original BSE repo, will be retained for legacy and reference, and because the code is old and stable and simple; but for advanced usage BSE2 should be the preferred choice once it is available.</i>\n\nBSE, The Bristol Stock Exchange, is a simple minimal simulation of a limit-order-book financial exchange, developed for teaching. The aim is to let students explore writing automated trading strategies that deal with \"Level 2\" market data.\n\nIt is written in Python, is single-threaded and all in one file for ease of use by novices. The file BSEguide.pdf explains much of what is going on and includes an example programming assignment. The Wiki here on the BSE GitHub site holds a copy of the BSEguide text: it may be that the Wiki text is more up to date than the PDF file. \n\nThe code in BSE is based on a large number of simplifying assumptions, chief of which is absolute-zero latency: if a trader issues a new quote, that gets processed by the exchange and all other traders can react to it, in zero time (i.e., before any other quote is issued). \n\nNevertheless, because the BSE system is stochastic it can also be used to introduce issues in the design of experiments and analysis of empirical data.\n\nReal exchanges are much much more complicated than this. \n\nIf you use BSE in your work, please link back to this GitHub page for BSE so that people know where to find the original Python source-code: https://github.com/davecliff/BristolStockExchange, and please also cite the peer-reviewed paper that describes BSE:\n \nCliff, D. (2018). BSE: A Minimal Simulation of a Limit-Order-Book Stock Exchange. In M. Affenzeller, et al. (Eds.), Proceedings 30th European Modeling and Simulation Symposium (EMSS 2018), pp. 194-203. DIME University of Genoa.\n \nWhich you can download from here:\nhttps://research-information.bris.ac.uk/ws/portalfiles/portal/167944812/Cliff_i3M_CRC_formatted_repository.pdf\n\nor here:\nhttps://arxiv.org/abs/1809.06027\n\n\nThe code is open-sourced via the MIT Licence: see the LICENSE file for full text. \n(copied from http://opensource.org/licenses/mit-license.php)\n\nLast update: Dave Cliff, March 27th 2024.\n"
  },
  {
    "path": "Trader_AA.py",
    "content": "'''\nCreated on 1 Dec 2012\n\n@author: Ash Booth\n\nAA order execution strategy as described in: \"Perukrishnen, Cliff and Jennings (2008) \n'Strategic Bidding in Continuous Double Auctions'. Artificial Intelligence Journal, \n172, (14), 1700-1729\".\n\n    With notable...\n    Amendments:\n    - slightly modified equilibrium price updating\n    - spin up period instead of rounds\n\n    Additions:\n    - Includes functions for using Newton-Rhapson method for finding \n      complementary theta values.\n\n'''\nimport math\nimport random\n\nclass Trader_AA(object):\n\n    def __init__(self):\n\n        # External parameters (you must choose [optimise] values yourselves)\n        self.spin_up_time = 20\n        self.eta = 3.0\n        self.theta_max = 2.0\n        self.theta_min = -8.0\n        self.lambda_a = 0.01\n        self.lambda_r = 0.02\n        self.beta_1 = 0.4\n        self.beta_2 = 0.4\n        self.gamma = 2.0\n        self.nLastTrades = 5  # N in AIJ08\n        self.ema_param = 2 / float(self.nLastTrades + 1)\n        self.maxNewtonItter = 10\n        self.maxNewtonError = 0.0001\n        \n        # The order we're trying to trade\n        self.orders = []\n        self.limit = None\n        self.active = False\n        self.job = None\n        \n        # Parameters describing what the market looks like and it's contstraints\n        self.marketMax = bse_sys_maxprice\n        self.prev_best_bid_p = None\n        self.prev_best_bid_q = None\n        self.prev_best_ask_p = None\n        self.prev_best_ask_q = None\n        \n        # Internal parameters (spin up time need to get values for some of these)\n        self.eqlbm = None\n        self.theta = -1.0 * (5.0 * random.random())\n        self.smithsAlpha = None\n        self.lastTrades = []\n        self.smithsAlphaMin = None\n        self.smithsAlphaMax = None\n        \n        self.aggressiveness_buy = -1.0 * (0.3 * random.random())\n        self.aggressiveness_sell = -1.0 * (0.3 * random.random())\n        self.target_buy = None\n        self.target_sell = None\n\n    def updateEq(self, price):\n        # Updates the equilibrium price estimate using EMA\n        if self.eqlbm == None: self.eqlbm = price\n        else: self.eqlbm = self.ema_param * price + (1 - self.ema_param) * self.eqlbm\n        \n    def newton4Buying(self):\n        # runs Newton-Raphson to find theta_est (the value of theta that makes the 1st \n        # derivative of eqn(3) continuous)\n        theta_est = self.theta\n        rightHside = ((self.theta * (self.limit - self.eqlbm)) / float(math.exp(self.theta) - 1));\n        i = 0\n        while i <= self.maxNewtonItter:\n            eX = math.exp(theta_est)\n            eXminOne = eX - 1\n            fofX = (((theta_est * self.eqlbm) / float(eXminOne)) - rightHside)\n            if abs(fofX) <= self.maxNewtonError:\n                break\n            dfofX = ((self.eqlbm / eXminOne) - ((eX * self.eqlbm * theta_est) / float(eXminOne * eXminOne)))\n            theta_est = (theta_est - (fofX / float(dfofX)));\n            i += 1\n        if theta_est == 0.0: theta_est += 0.000001\n        return theta_est\n    \n    def newton4Selling(self):\n        # runs Newton-Raphson to find theta_est (the value of theta that makes the 1st \n        # derivative of eqn(4) continuous)\n        theta_est = self.theta\n        rightHside = ((self.theta * (self.eqlbm - self.limit)) / float(math.exp(self.theta) - 1))\n        i = 0\n        while i <= self.maxNewtonItter:\n            eX = math.exp(theta_est)\n            eXminOne = eX - 1\n            fofX = (((theta_est * (self.marketMax - self.eqlbm)) / float(eXminOne)) - rightHside)\n            if abs(fofX) <= self.maxNewtonError:\n                break\n            dfofX = (((self.marketMax - self.eqlbm) / eXminOne) - ((eX * (self.marketMax - self.eqlbm) * theta_est) / float(eXminOne * eXminOne)))\n            theta_est = (theta_est - (fofX / float(dfofX)))\n            i += 1\n        if theta_est == 0.0: theta_est += 0.000001\n        return theta_est\n        \n    def updateTarget(self):\n        # relates to eqns (3),(4),(5) and (6)\n        # For buying\n        if self.limit < self.eqlbm:\n            # Extra-marginal buyer\n            if self.aggressiveness_buy >= 0: target = self.limit\n            else: target = self.limit * (1 - (math.exp(-self.aggressiveness_buy * self.theta) - 1) / float(math.exp(self.theta) - 1))\n            self.target_buy = target\n        else:\n            # Intra-marginal buyer\n            if self.aggressiveness_buy >= 0: target = (self.eqlbm + (self.limit - self.eqlbm) * ((math.exp(self.aggressiveness_buy * self.theta) - 1) / float(math.exp(self.theta) - 1)))\n            else:\n                theta_est = self.newton4Buying()\n                target = self.eqlbm * (1 - (math.exp(-self.aggressiveness_buy * theta_est) - 1) / float(math.exp(theta_est) - 1))\n            self.target_buy = target\n        # For selling\n        if self.limit > self.eqlbm:\n            # Extra-marginal seller\n            if self.aggressiveness_sell >= 0: target = self.limit\n            else: target = self.limit + (self.marketMax - self.limit) * ((math.exp(-self.aggressiveness_sell * self.theta) - 1) / float(math.exp(self.theta) - 1))\n            self.target_sell = target\n        else:\n            # Intra-marginal seller\n            if self.aggressiveness_sell >= 0: target = self.limit + (self.eqlbm - self.limit) * (1 - (math.exp(self.aggressiveness_sell * self.theta) - 1) / float(math.exp(self.theta) - 1))\n            else:\n                theta_est = self.newton4Selling() \n                target = self.eqlbm + (self.marketMax - self.eqlbm) * ((math.exp(-self.aggressiveness_sell * theta_est) - 1) / (math.exp(theta_est) - 1))\n            self.target_sell = target\n    \n    def calcRshout(self, target, buying):\n        if buying:\n            # Are we extramarginal?\n            if self.eqlbm >= self.limit:\n                r_shout = 0.0\n            else:  # Intra-marginal\n                if target > self.eqlbm:\n                    if target > self.limit: target = self.limit\n                    r_shout = math.log((((target - self.eqlbm) * (math.exp(self.theta) - 1)) / (self.limit - self.eqlbm)) + 1) / self.theta\n                else:  # other formula for intra buyer\n                    r_shout = math.log((1 - (target / self.eqlbm)) * (math.exp(self.newton4Buying()) - 1) + 1) / -self.newton4Buying()\n        else:  # Selling\n            # Are we extra-marginal?\n            if self.limit >= self.eqlbm:\n                r_shout = 0.0\n            else:  # Intra-marginal\n                if target > self.eqlbm:\n                    r_shout = math.log(((target - self.eqlbm) * (math.exp(self.newton4Selling()) - 1)) / (self.marketMax - self.eqlbm) + 1) / -self.newton4Selling()\n                else:  # other intra seller formula\n                    if target < self.limit: target = self.limit\n                    r_shout = math.log((1 - (target - self.limit) / (self.eqlbm - self.limit)) * (math.exp(self.theta) - 1) + 1) / self.theta\n        return r_shout\n    \n    def updateAgg(self, up, buying, target):\n        if buying:\n            old_agg = self.aggressiveness_buy \n        else:\n            old_agg = self.aggressiveness_sell\n        if up:\n            delta = (1 + self.lambda_r) * self.calcRshout(target, buying) + self.lambda_a\n        else:\n            delta = (1 - self.lambda_r) * self.calcRshout(target, buying) - self.lambda_a\n        new_agg = old_agg + self.beta_1 * (delta - old_agg)\n        if new_agg > 1.0: new_agg = 1.0\n        elif new_agg < 0.0: new_agg = 0.000001\n        return new_agg\n    \n    def updateSmithsAlpha(self, price):\n        self.lastTrades.append(price)\n        if not (len(self.lastTrades) <= self.nLastTrades): self.lastTrades.pop(0)\n        self.smithsAlpha = math.sqrt(sum(((p - self.eqlbm) ** 2) for p in self.lastTrades) * (1 / float(len(self.lastTrades)))) / self.eqlbm\n        if self.smithsAlphaMin == None:\n            self.smithsAlphaMin = self.smithsAlpha\n            self.smithsAlphaMax = self.smithsAlphaMax\n        else:\n            if self.smithsAlpha < self.smithsAlphaMin: self.smithsAlphaMin = self.smithsAlpha\n            if self.smithsAlpha > self.smithsAlphaMax: self.smithsAlphaMax = self.smithsAlpha\n        \n    def updateTheta(self):\n        alphaBar = (self.smithsAlpha - self.smithsAlphaMin) / (self.smithsAlphaMax - self.smithsAlphaMin)\n        desiredTheta = (self.theta_max - self.theta_min) * (1 - (alphaBar * math.exp(self.gamma * (alphaBar - 1)))) + self.theta_min\n        theta = self.theta + self.beta_2 * (desiredTheta - self.theta)\n        if theta == 0: theta += 0.0000001\n        self.theta = theta\n    \n    def getorder(self, time, countdown, lob):\n        if len(self.orders) < 1:\n            self.active = False\n            order = None\n        else:\n            self.active = True\n            self.limit = self.orders[0].price\n            self.job = self.orders[0].otype\n            self.updateTarget()\n            if self.job == 'Bid':\n                # currently a buyer (working a bid order)\n                if self.spin_up_time > 0:\n                    ask_plus = (1 + self.lambda_r) * self.prev_best_ask_p + self.lambda_a\n                    quoteprice = self.prev_best_bid_p + (min(self.limit, ask_plus) - self.prev_best_bid_p) / self.eta\n                else:\n                    quoteprice = self.prev_best_bid_p + (self.target - self.prev_best_bid_p) / self.eta\n            else:\n                # currently a seller (working a sell order)\n                if self.spin_up_time > 0:\n                    bid_minus = (1 - self.lambda_r) * self.prev_best_bid_p - self.lambda_a\n                    quoteprice = self.prev_best_ask_p - (self.prev_best_ask_p - max(self.limit, bid_minus)) / self.eta\n                else:\n                    quoteprice = (self.prev_best_ask_p - (self.prev_best_ask_p - self.target) / self.eta)\n        \n            order = Order(self.tid, self.job, quoteprice, self.orders[0].qty, time)\n        \n        return order             \n            \n        \n    def respond(self, time, lob, trade, verbose):\n        # what, if anything, has happened on the bid LOB?\n        bid_improved = False\n        bid_hit = False\n        lob_best_bid_p = lob['bids']['best']\n        lob_best_bid_q = None\n        if lob_best_bid_p != None:\n            # non-empty bid LOB\n            lob_best_bid_q = lob['bids']['lob'][-1][1]\n            if self.prev_best_bid_p < lob_best_bid_p :\n                # best bid has improved\n                # NB doesn't check if the improvement was by self\n                bid_improved = True\n            elif trade != None and ((self.prev_best_bid_p > lob_best_bid_p) or ((self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\n                # previous best bid was hit\n                bid_hit = True\n        elif self.prev_best_bid_p != None:\n            # the bid LOB has been emptied by a hit\n                bid_hit = True\n\n        # what, if anything, has happened on the ask LOB?\n        ask_improved = False\n        ask_lifted = False\n        lob_best_ask_p = lob['asks']['best']\n        lob_best_ask_q = None\n        if lob_best_ask_p != None:\n            # non-empty ask LOB\n            lob_best_ask_q = lob['asks']['lob'][0][1]\n            if self.prev_best_ask_p > lob_best_ask_p :\n                # best ask has improved -- NB doesn't check if the improvement was by self\n                ask_improved = True\n            elif trade != None and ((self.prev_best_ask_p < lob_best_ask_p) or ((self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\n                # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\n                ask_lifted = True\n        elif self.prev_best_ask_p != None:\n            # the bid LOB is empty now but was not previously, so must have been hit\n            ask_lifted = True\n\n        if verbose and (bid_improved or bid_hit or ask_improved or ask_lifted):\n            print ('B_improved', bid_improved, 'B_hit', bid_hit, 'A_improved', ask_improved, 'A_lifted', ask_lifted)\n\n        deal = bid_hit or ask_lifted\n        self.prev_best_bid_p = lob_best_bid_p\n        self.prev_best_ask_p = lob_best_ask_p\n        \n        \n        if self.spin_up_time > 0: self.spin_up_time -= 1\n        if deal:\n            price = trade['price']\n            self.updateEq(price)\n            self.updateSmithsAlpha(price)\n            self.updateTheta()\n        \n        # The lines below represent the rules in fig(7) in AIJ08. The if statements have not\n        # been merged for the sake of clarity.\n        \n        # For buying\n        if deal:\n            if self.target >= price: \n                self.aggressiveness_buy = self.updateAgg(False, True, price)\n            else: self.aggressiveness_buy = self.updateAgg(True, True, price)\n        elif bid_improved and (self.target <= price): self.aggressiveness_buy = self.updateAgg(True, True, self.prev_best_bid_p)\n        # For selling\n        if deal:\n            if self.target <= price:  self.aggressiveness_sell = self.updateAgg(False, False, price)\n            else: self.aggressiveness_sell = self.updateAgg(True, False, price)\n        elif ask_improved and (self.target >= price): self.aggressiveness_sell = self.updateAgg(True, False, self.prev_best_ask_p)\n        \n        self.updateTarget()\n        \n"
  },
  {
    "path": "ZhenZhang/README.md",
    "content": "This folder holds the sourcecode developed by Zhen Zhang as part of his MSc project, supervised by Dave Cliff, at the University of Bristol, submitted in September 2020.\n\n\n\nThe main contribution is to adapt the multi-level order flow imbalance (MLOFI) to IAA.\n\nIt includes two modules:\n\n+ \"impact-sensitive\" module\n+ \"evaluation\" module\n\n\n\nIn [IAA_MLOFI.py](./source/IAA_MLOFI.py), it is  the IAA with  \"impact-sensitive\" module.\n\nIn [IAA_NEW.py](./source/IAA_NEW.py), it is the IAA with two modules.\n\nIn [IZIP_MLOFI.py](./source/IZIP_MLOFI.py), it is the ZZIZIP.\n\nIn [ZZISHV.py](./source/ZZISHV.py), it is the ZZISHV.\n\n"
  },
  {
    "path": "ZhenZhang/source/BSE2.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# BSE: The Bristol Stock Exchange\n#\n# Version 2.0Beta: Nov 20th, 2018.\n# Version 1.4: August 30th, 2018.\n# Version 1.3: July 21st, 2018.\n# Version 1.2: November 17th, 2012.\n#\n# Copyright (c) 2012-2019, Dave Cliff\n#\n#\n# ------------------------\n#\n# MIT Open-Source License:\n# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and\n# associated documentation files (the \"Software\"), to deal in the Software without restriction,\n# including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\n# and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,\n# subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in all copies or substantial\n# portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT\n# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n#\n# ------------------------\n#\n#\n#\n# BSE is a very simple simulation of automated execution traders\n# operating on a very simple model of a limit order book (LOB) exchange\n#\n# major simplifications in this version:\n#       (a) only one financial instrument being traded\n#       (b) each trader can have max of one order per single orderbook.\n#       (c) simply processes each order in sequence and republishes LOB to all traders\n#           => no issues with exchange processing latency/delays or simultaneously issued orders.\n#\n# NB this code has been written to be readable/intelligible, not efficient!\n\n# could import pylab here for graphing etc\n\nimport sys\nimport math\nimport random\nimport csv\nfrom datetime import datetime\n\nfrom BSE2_msg_classes import Assignment, Order, Exch_msg\nfrom BSE_trader_agents import Trader_ISHV, Trader_Shaver,Trader_Giveaway,Trader_AA, Trader_Sniper, Trader_ZIC,Trader_ZIP,Trader_OAA #, Trader_IAAB\nfrom IZIP_MLOFI import Trader_IZIP_MLOFI\nfrom IAA_MLOFI import Trader_IAA_MLOFI\nfrom Simple_MLOFI import Trader_Simple_MLOFI\nfrom GDX import  Trader_GDX\nfrom IGDX_MLOFI import Trader_IGDX_MLOFI\nfrom IAA_NEW import Trader_IAA_NEW\nfrom ZZISHV import Trader_ZZISHV\n\n# from BSE2_unittests import test_all\n# from BSE2_dev import proc_OXO proc_ICE\n\n\nbse_sys_minprice = 1  # minimum price in the system, in cents/pennies\nbse_sys_maxprice = 200  # maximum price in the system, in cents/pennies: Todo -- eliminate reliance on this\nticksize = 1  # minimum change in price, in cents/pennies\n\n\n\n# Orderbook_half is one side of the book:\n# The internal records of the exchange include the ID of the trader who issued the order, arrival time, etc.\n# The externally published LOB aggregates and anonymizes these details.\n\nclass Orderbook_half:\n\n        def __init__(self, booktype, worstprice):\n\n                self.booktype = booktype\n\n                def bid_equaltoorbetterthan(p1, p2, verbose):\n                        if verbose: print(\"bid_equaltoorbetterthan: %d >= %d ?\" % (p1, p2))\n                        if p1 >= p2: return(True)\n                        else: return(False)\n\n                def ask_equaltoorbetterthan(p1, p2, verbose):\n                        if verbose: print(\"ask_equaltoorbetterthan: %d <= %d ?\" % (p1, p2))\n                        if p1 <= p2: return(True)\n                        else: return(False)\n\n                # function for deciding whether price A is equal to or better than price B\n                if self.booktype == 'Bid':\n                        self.equaltoorbetterthan = bid_equaltoorbetterthan\n                elif self.booktype == 'Ask':\n                        self.equaltoorbetterthan = ask_equaltoorbetterthan\n                else: sys.exit('Fail: Orderbook_half __init__ passed booktype=%s', str(booktype))\n\n                # dictionary of live orders received, indexed by Order ID\n                self.orders = {}\n                # limit order book, exchange's internal list, ordered by price, with associated order info\n                self.lob = []\n                # anonymized LOB, aggregated list with only price/qty info: as published to market observers\n                self.lob_anon = []\n                # list of orders \"resting\" at the exchange, i.e. orders that persist for some time (e.g. AON, ICE)\n                self.resting = []\n                # On-Close & On-Open hold LIM & MKT orders that execute at market open and close (MOO, MOC, LOO, LOC)\n                self.on_close = []\n                self.on_open = []\n                # OXO stores details of \"other\" for OSO and OCO orders\n                self.oxo = []\n                # summary stats\n                # self.best_price = None\n                self.worst_price = worstprice\n                # self.n_orders = 0  # how many orders?\n                # self.lob_depth = 0  # how many different prices on lob?\n\n\n        def __str__(self):\n                v = 'OB_H> '\n                s = '\\n' + v + self.booktype + '\\n'\n                s = s + v + 'Orders: '\n                for oid in self.orders:\n                        s = s + str(oid) + '=' + str(self.orders[oid]) + ' '\n                s = s + '\\n'\n                s = s + v + 'LOB:\\n'\n                for row in self.lob:\n                        s = s + '[P=%d,[' % row[0] # price\n                        for order in row[1]:\n                                s = s + '[T=%5.2f Q=%d %s OID:%d]' % (order[0], order[1], order[2], order[3])\n                        s = s + ']]\\n'\n                s = s + v + 'LOB_anon' + str(self.lob_anon) + '\\n'\n                s = s + v + 'MOB:'\n                s = s + '\\n'\n\n                return s\n\n\n        def anonymize_lob(self, verbose):\n                # anonymize a lob, strip out order details, format as a sorted list\n                # sorting is best prices at the front (LHS) of the list\n                self.lob_anon = []\n                if self.booktype == 'Bid':\n                        for price in sorted(self.lob, reverse=True):\n                                qty = self.lob[price][0]\n                                self.lob_anon.append([price, qty])\n                elif self.booktype == 'Ask':\n                        for price in sorted(self.lob):\n                                qty = self.lob[price][0]\n                                self.lob_anon.append([price, qty])\n                else:\n                        sys.exit('Fail: Orderbook_half __init__ passed booktype=%s', str(booktype))\n                if verbose: print self.lob_anon\n\n\n        def build_lob(self, verbose):\n                # take a list of orders and build a limit-order-book (lob) from it\n                # NB the exchange needs to know arrival times and trader-id associated with each order\n                # returns lob as a list, sorted by price best to worst, orders at same price sorted by arrival time\n                # also builds aggregated & anonymized version (just price/quantity, sorted, as a list) for publishing to traders\n\n                # First builds lob as a dictionary indexed by price\n                lob = {}\n                for oid in self.orders:\n                        order = self.orders.get(oid)\n                        price = int(order.price)\n                        if price in lob:\n                                # update existing entry\n                                qty = lob[price][0]\n                                orderlist = lob[price][1]\n                                orderlist.append([order.time, order.qty, order.tid, order.orderid])\n                                lob[price] = [qty + order.qty, orderlist]\n                        else:\n                                # create a new dictionary entry\n                                lob[price] = [order.qty, [[order.time, order.qty, order.tid, order.orderid]]]\n\n                self.lob = []\n                for price in lob:\n                        orderlist = lob[price][1]\n                        orderlist.sort() #orders are sorted by arrival time\n                        self.lob.append([price, orderlist]) #appends only the price and the order-list\n                # now sort by price: order depends on book type\n                if self.booktype == 'Bid':\n                        self.lob.sort(reverse=True)\n                elif self.booktype == 'Ask':\n                        self.lob.sort()\n                else:\n                        sys.exit('Fail: Orderbook_half __init__ passed booktype=%s', str(booktype))\n\n                # create anonymized version of LOB for publication\n                self.lob_anon = []\n                if self.booktype == 'Bid':\n                        for price in sorted(lob, reverse=True):\n                                qty = lob[price][0]\n                                self.lob_anon.append([price, qty])\n                else:\n                        for price in sorted(lob):\n                                qty = lob[price][0]\n                                self.lob_anon.append([price, qty])\n\n                if verbose: print self.lob_anon\n\n                # record best price and associated trader-id\n                if len(self.lob) > 0 :\n                        if self.booktype == 'Bid':\n                                self.best_price = self.lob_anon[-1][0] #assumes reverse order COME BACK HERE\n                        else :\n                                self.best_price = self.lob_anon[0][0]\n                else :\n                        self.best_price = None\n\n                if verbose: print self.lob\n\n\n        def book_add(self, order, verbose):\n                # add an order to the master list holding the orders\n                if verbose: print('>book_add %s' % (order))\n                self.orders[order.orderid] = order\n                self.n_orders = len(self.orders)\n                # reconstruct the LOB -- from scratch (inefficient)\n                self.build_lob(verbose)\n                return None #null response\n\n\n        def book_CAN(self, time, order, pool_id, verbose):\n                # delete (CANcel) an order from the dictionary holding the orders\n\n                def add_tapeitem(eventlist, pool_id, time, oid, otype, qty, verbose):\n                        # add_tapeitem(): add an event to list of events that will be written to tape\n                        tape_event = {'pool_id':pool_id, 'type':'CAN', 'time':time, 'oid':oid, 'otype':otype, 'o_qty':qty}\n                        eventlist.append(tape_event)\n                        if verbose: print('book_CAN.add_tapeitem() trans_event=%s' % tape_event)\n\n                tape_events=[]\n\n                if verbose:\n                        print('>OrderbookHalf.book_CAN %s' % order)\n                        for ord in self.orders: print(\"{%s: %s}\" % (ord,str(self.orders[ord])))\n\n                oid = order.orderid\n                if len(self.orders)>0 and (self.orders.get(oid) != None) :\n                        if verbose: print('Deleting order %s' % oid)\n                        o_qty = self.orders[oid].qty\n                        o_type = self.booktype\n                        del(self.orders[oid])\n                        self.n_orders = len(self.orders)\n                        # reconstruct the LOB -- from scratch (inefficient)\n                        self.build_lob(verbose)\n                        if verbose: print('<book_CAN %s' % self.orders)\n\n                        tmsg = Exch_msg(order.tid, oid, \"CAN\", [], None, 0, 0)\n                        add_tapeitem(tape_events, pool_id, time, oid, o_type, o_qty, verbose)\n\n                        return {\"TraderMsgs\":[tmsg], \"TapeEvents\":tape_events}\n                else:\n                        print oid\n                        print 'NOP' # no operation -- order ID not in the order dictionary\n                        sys.exit('Fail: book_CAN() attempts to delete nonexistent order ')\n\n\n        def book_take(self, time, order, pool_id, verbose):\n                # process the order by taking orders off the LOB, consuming liquidity at the top of the book\n                # this is where (MKT, IOC, FOK, AON) orders get matched and execute\n                # returns messages re transactions, to be sent to traders involved; and a list of events to write to the tape\n                # MKT order consumes the specified quantity, if available: partial fills allowed; ignores the price (so watch out for loss-making trades)\n                # FOK only completes if it can consume the specified quantity at prices equal to or better than the specified price\n                # IOC executes as much as it can of the specified quantity; allows partial fill: unfilled portion of order is cancelled\n                # AON is like FOK but rests at the exchange until either (a) it can do complete fill or (b) clock reaches specified expiry time, at which point order cancelled.\n                # NB the cancellations are not written to the tape, because they do not take liquidity away from the LOB\n\n\n                def add_msg(msglist, tid, oid, etype, transactions, rev_order, fee, verbose):\n                        # add_msg(): add a message to list of messages from exchange back to traders\n                        # each msg tells trader [tid] that [OID] resulted in an event-type from [PART|FILL|FAIL]\n                        # if PART then also sends back [revised order] -- telling the trader what the LOB retains as the unfilled portion\n                        # if FILL then [revised order] is None\n                        # message concludes with bank-balance details: exchange fee & trader's balance at exchange\n                        msg = Exch_msg(tid, oid, etype, transactions, rev_order, fee, 0)\n                        msglist.append(msg)\n                        if verbose: print(msg)\n\n\n                def add_tapeitem(eventlist, pool_id, eventtype, time, price, qty, party_from, party_to, verbose):\n                        # add_tapeitem(): add an event to list of events that will be written to tape\n                        # event type within book_take should be 'Trade'\n                        tape_event = { 'pool_id': pool_id,\n                                       'type': eventtype,\n                                       'time': time,\n                                       'price': price,\n                                       'qty': qty,\n                                       'party1': party_from,\n                                       'party2': party_to}\n                        eventlist.append(tape_event)\n                        if verbose: print('add_tapeitem() tape_event=%s' % tape_event)\n\n\n                msg_list = []           # details of orders consumed from the LOB when filling this order\n                trnsctns = []           # details of transactions resulting from this incoming order walking the book\n                tape_events = []        # details of transaction events to be written onto tape\n                qty_filled = 0          # how much of this order have we filled so far?\n                fee = 0               # exchange fee charged for processing this order (taking liquidity, wrt maker-taker)\n\n                if verbose: print('>book_take(): order=%s, lob=%s' % (order, self.lob))\n\n\n                # initial checks, return FAIL if there is simply no hope of executing this order\n\n                if len(self.lob) == 0:\n                        # no point going any further; LOB is empty\n                        add_msg(msg_list, order.tid, order.orderid, \"FAIL\", [], None, fee, verbose)\n                        return {\"TraderMsgs\": msg_list, \"TapeEvents\": tape_events}\n\n                # how deep is the book? (i.e. what is cumulative qty available) at this order's indicated price level?\n                depth = 0\n                for level in self.lob_anon:\n                        if self.equaltoorbetterthan(level[0], order.price, verbose):\n                                depth += level[1]\n                        else:  # we're past the level in the LOB where the prices are good for this order\n                                break\n\n                if order.ostyle == \"FOK\" or order.ostyle == \"AON\":\n                        # FOK and AON require a complete fill\n                        # so we first check that this order can in principle be filled: is there enough liquidity available?\n                        if depth < order.qty:\n                                # there is not enough depth at prices that allow this order to completely fill\n                                add_msg(msg_list, order.tid, order.oid, \"FAIL\", [], None, fee, verbose)\n                                # NB here book_take() sends a msg back that an AON order is FAIL, that needs to be picked up by the\n                                # exchange logic and not passed back to the trader concerned, unless the AON has actually timed out\n                                return {\"TraderMsgs\": msg_list, \"TapeEvents\": tape_events}\n\n                if order.ostyle == \"IOC\" and depth < 1 :\n                        # IOC order is a FAIL because there is no depth at all for the indicated price\n                        add_msg(msg_list, order.tid, order.orderid, \"FAIL\", [], None, fee, verbose)\n                        return {\"TraderMsgs\": msg_list, \"TapeEvents\": tape_events}\n\n\n                # we only get this far if...\n                # LOB is not empty\n                # order is FOK or AON (complete fill only) --  we know there's enough depth to complete\n                # order is MKT (allows partial fill, ignores prices, stops when indicated quantity is reached or LOB is empty)\n                # order is IOC (allows partial fill, aims for indicated quantity but stops when price-limit is reached or LOB is empty) and LOB depth at price > 0\n\n                if order.otype == \"Bid\":\n                        tid_to = order.tid\n                        oid_to = order.orderid\n                elif order.otype == \"Ask\":\n                        tid_from = order.tid\n                        oid_from = order.orderid\n                else: # this shouldn't happen\n                        sys.exit('>book_take: order.otype=%s in book_take' % order.otype)\n\n                # make a copy of the order-list and lobs as it initially stands\n                # used for reconciling fills and when order is abandoned because it can't complete (e.g. FOK, AON)\n                # initial_orders = self.orders\n\n                # work this order by \"walking the book\"\n\n                qty_remaining = order.qty\n\n                best_lob_price = self.lob[0][0]\n\n                good_price = True\n\n                if order.ostyle != \"MKT\":\n                        good_price = self.equaltoorbetterthan(best_lob_price, order.price, verbose)\n\n                # this while loop consumes the top of the LOB while trying to fill the order\n                while good_price and (qty_remaining > 0) and (len(self.orders)>0):\n\n                        good_price = self.equaltoorbetterthan(self.lob[0][0], order.price, verbose)\n\n                        if verbose:\n                                print('BK_TAKE: qty_rem=%d; lob=%s; good_price=%s' % (qty_remaining, str(self.lob), good_price))\n                                sys.stdout.flush()\n\n                        if order.ostyle == \"IOC\" and (not good_price):\n                                # current LOB best price is unacceptable for IOC\n                                if verbose: print(\n                                                'BK_TAKE: IOC breaks out of while loop (otype=%s best LOB price = %d; order price = %d)' %\n                                                (order.otype, self.lob[0][0], order.price))\n                                break  # out of the while loop\n\n                        best_lob_price = self.lob[0][0]\n                        best_lob_orders = self.lob[0][1]\n                        best_lob_order = best_lob_orders[0]\n                        best_lob_order_qty = best_lob_order[1]\n                        best_lob_order_tid = best_lob_order[2]\n                        best_lob_order_oid = best_lob_order[3]\n                        if order.otype == \"Bid\":\n                                tid_from = best_lob_order_tid\n                                oid_from = best_lob_order_oid\n                        elif order.otype == \"Ask\":\n                                tid_to = best_lob_order_tid\n                                oid_to = best_lob_order_oid\n\n                        if verbose: print('BK_TAKE: best_lob _price=%d _order=%s qty=%d oid_from=%d oid_to=%d tid_from=%s tid_to=%s\\n' %\n                                          (best_lob_price, best_lob_order, best_lob_order_qty, oid_from, oid_to, tid_from, tid_to))\n\n\n                        # walk the book: does this order consume current best order on book?\n                        if best_lob_order_qty >= qty_remaining:\n\n                                # incoming liquidity-taking order is completely filled by consuming some/all of best order on LOB\n                                qty = qty_remaining\n                                price = best_lob_price\n                                qty_filled = qty_filled + qty\n                                best_lob_order_qty = best_lob_order_qty - qty\n                                # the incoming order is a complete fill\n                                transaction = {\"Price\":price, \"Qty\":qty}\n                                trnsctns.append(transaction)\n\n                                # add a message to the list of outgoing messages from exch to traders\n                                add_msg(msg_list, order.tid, order.orderid, \"FILL\", trnsctns, None, fee, verbose)\n\n                                # add a record of this to the tape (NB this identifies both parties to the trade, so only do it once)\n                                add_tapeitem(tape_events, pool_id, 'Trade', time, price, qty, tid_from, tid_to, verbose)\n\n                                # so far have dealt with effect of match on incoming order\n                                # now need to deal with effect of match on best order on LOB (the other side of the deal)\n                                if best_lob_order_qty > 0:\n                                        # the best LOB order is only partially consumed\n                                        best_lob_order[1] = best_lob_order_qty\n                                        best_lob_orders[0] = best_lob_order\n                                        self.lob[0][1] = best_lob_orders\n                                        self.orders[best_lob_order_oid].qty = best_lob_order_qty\n                                        # The LOB order it matched against is only a partial fill\n                                        add_msg(msg_list, best_lob_order_tid, best_lob_order_oid, \"PART\", [transaction], self.orders[best_lob_order_oid], fee, verbose)\n                                        # add_tapeitem(tape_events, 'Trade', time, price, qty, tid_from, tid_to, verbose)\n                                else:\n                                        # the best LOB order is fully consumed: delete it from LOB\n                                        del(best_lob_orders[0])\n                                        del(self.orders[best_lob_order_oid])\n                                        # The LOB order it matched against also complete\n                                        add_msg(msg_list, best_lob_order_tid, best_lob_order_oid, \"FILL\", [transaction], None, fee, verbose)\n                                        # add_tapeitem(tape_events, 'Trade', time, price, qty, tid_from, tid_to, verbose)\n                                        # check: are there other remaining orders at this price?\n                                        if len(best_lob_orders) > 0:\n                                                # yes\n                                                self.lob[0][1] = best_lob_orders\n                                        else:\n                                                # no\n                                                del (self.lob[0])  # consumed the last order on the LOB at this price\n                                qty_remaining = 0  # liquidity-taking all done\n                        else:\n                                # order is only partially filled by current best order, but current best LOB order is fully filled\n                                # consume all the current best and repeat\n                                qty = best_lob_order_qty\n                                price = best_lob_price\n                                qty_filled = qty_filled + qty\n                                transaction = {\"Price\": price, \"Qty\": qty}\n                                trnsctns.append(transaction)\n\n                                # add a message to the list of outgoing messages from exch to traders\n                                add_msg(msg_list, best_lob_order_tid, best_lob_order_oid, \"FILL\", [transaction], None, fee, verbose)\n\n                                # add a record of this to the tape (NB this identifies both parties to the trade, so only do it once)\n                                add_tapeitem(tape_events, pool_id, 'Trade', time, price, qty, tid_from, tid_to, verbose)\n\n                                # the best LOB order is fully consumed: delete it from LOB and from order-list\n                                del(self.orders[best_lob_order_oid])\n                                del(best_lob_orders[0])\n\n                                # check: are there other remaining orders at this price?\n                                if len(best_lob_orders) > 0:\n                                        # yes\n                                        self.lob[0][1] = best_lob_orders\n                                else:\n                                        # no\n                                        del (self.lob[0])  # consumed the last order on the LOB at this price\n\n                                qty_remaining = qty_remaining - qty\n                                if verbose: print('New LOB=%s orders=%s' % (str(self.lob), str(self.orders)))\n\n                # main while loop ends here\n\n                # when we get to here either...\n                # the order completely filled by consuming the front of the book (which may have emptied the whole book)\n                # or the whole book was consumed (and is now empty) without completely filling the order\n                # or IOC consumed as much of the book's availability at the order's indicated price (good_price = False)\n\n                if qty_remaining > 0 :\n                        if qty_remaining == order.qty:\n                                # this order is wholly unfilled: that's a FAIL (how did this get past the initial checks?)\n                                add_msg(msg_list, order.tid, order.orderid, \"FAIL\", [], None, fee, verbose)\n                        else:\n                                # this liquidity-taking order only partially filled but ran out of usable LOB\n                                order.qty = qty_remaining #revise the order quantity\n                                add_msg(msg_list, order.tid, order.orderid, \"PART\", trnsctns, order, fee, verbose)\n                                # add_tapeitem(tape_events, 'Trade', time, price, qty, tid_from, tid_to, verbose)\n\n                if verbose:\n                        print('<Orderbook_Half.book_take() TapeEvents=%s' % tape_events)\n                        print('<Orderbook_Half.book_take() TraderMsgs=')\n                        for msg in msg_list:\n                                print('%s,' % str(msg))\n                        print('\\n')\n\n                # rebuild the lob to reflect the adjusted order list\n                self.build_lob(verbose)\n\n                return {\"TraderMsgs\":msg_list, \"TapeEvents\":tape_events}\n\n\n\n# Orderbook for a single instrument: list of bids and list of asks and methods to manipulate them\n\nclass Orderbook(Orderbook_half):\n\n\n        def __init__(self, id_string):\n                self.idstr = id_string          # give it a name\n                self.bids = Orderbook_half('Bid', bse_sys_minprice)\n                self.asks = Orderbook_half('Ask', bse_sys_maxprice)\n                self.ob_tape = []               # tape of just this orderbook's activities (may be consolidated at Exchange level)\n                self.last_trans_t = None        # time of last transaction\n                self.last_trans_p = None        # price of last transaction\n                self.last_trans_q = None        # quantity of last transaction\n\n\n        def __str__(self):\n                s = 'Orderbook:\\n'\n                s = s + 'Bids: %s \\n' % str(self.bids)\n                s = s + 'Asks: %s \\n' % str(self.asks)\n                s = s + 'Tape[-5:]: %s \\n' % str(self.ob_tape[-5:])\n                s = s + '\\n'\n                return s\n\n\n        def midprice(self, bid_p, bid_q, ask_p, ask_q):\n                # returns midprice as mean of best bid and best ask if both best bid & best ask exist\n                # if only one best price exists, returns that as mid\n                # if neither best price exists, returns None\n                mprice = None\n                if bid_q > 0 and ask_q == None :\n                        mprice = bid_p\n                elif ask_q > 0 and bid_q == None :\n                        mprice = ask_p\n                elif bid_q>0 and ask_q >0 :\n                        mprice = ( bid_p + ask_p ) / 2.0\n                return mprice\n\n\n        def microprice(self, bid_p, bid_q, ask_p, ask_q):\n                mprice = None\n                if bid_q>0 and ask_q >0 :\n                        tot_q = bid_q + ask_q\n                        mprice = ( (bid_p * ask_q) + (ask_p * bid_q) ) / tot_q\n                return mprice\n\n\n        def add_lim_order(self, order, verbose):\n                # add a LIM order to the LOB and update records\n                if verbose: print('>add_lim_order: order.orderid=%d' % (order.orderid))\n                if order.otype == 'Bid':\n                        response=self.bids.book_add(order, verbose)\n                        best_price = self.bids.lob_anon[0][0]\n                        self.bids.best_price = best_price\n                else:\n                        response=self.asks.book_add(order, verbose)\n                        best_price = self.asks.lob_anon[0][0]\n                        self.asks.best_price = best_price\n                return response\n\n\n        def process_order_CAN(self, time, order, verbose):\n\n                # cancel an existing order\n                if verbose: print('>Orderbook.process_order_CAN order.orderid=%d' % order.orderid)\n\n                if order.otype == 'Bid':\n                        # cancel order from the bid book\n                        response = self.bids.book_CAN(time, order, self.idstr, verbose)\n                elif order.otype == 'Ask':\n                        # cancel order from the ask book\n                        response = self.asks.book_CAN(time, order, self.idstr, verbose)\n                else:\n                        # we should never get here\n                        sys.exit('process_order_CAN() given neither Bid nor Ask')\n\n                # response should be a message for the trader, and an event to write to the tape\n\n                if verbose: print('PO_CAN %s' % response)\n\n                return response\n\n\n        def process_order_XXX(self, time, order, verbose):\n\n                # cancel all orders on this orderbook that were issued by the trader that issued this order\n                if verbose: print('>Orderbook.process_order_XXX order.orderid=%d' % order.orderid)\n\n                tid = order.tid\n                # need to sweep through all bids and and all asks and delete all orders from this trader\n\n                responselist = []\n\n                for bid_order in self.bids.orders:\n                        if bid_order.tid == tid :\n                                responselist.append(self.bids.book_CAN(time, order, verbose))\n\n                for ask_order in self.asks.orders:\n                        if ask_order.tid == tid:\n                                responselist.append(self.asks.book_CAN(time, order, verbose))\n\n                # responselist is handed back to caller level for them to unpack\n\n                if verbose: print('PO_CAN %s' % responselist)\n\n                return responselist\n\n\n        def process_order_take(self, time, order, verbose):\n\n                if verbose: print('> Orderbook.process_order_take order.orderid=%d' % order.orderid)\n\n                if order.otype == 'Bid':\n                        # this bid consumes from the top of the ask book\n                        response = self.asks.book_take(time, order, self.idstr, verbose)\n                elif order.otype == 'Ask':\n                        # this ask consumes from the top of the bid book\n                        response = self.bids.book_take(time, order, self.idstr, verbose)\n                else:   # we should never get here\n                        sys.exit('process_order_take() given neither Bid nor Ask')\n\n                if verbose: print('OB.PO_take %s' % response)\n\n                return response\n\n\n        def process_order_LIM(self, time, order, verbose):\n\n                # adds LIM and GFD orders -- GFD is just a time-limited LIM\n\n                def process_LIM(order, verbose):\n                        response = self.add_lim_order(order, verbose)\n\n                        if verbose:\n                                print('>process_order_LIM order.orderid=%d' % order.orderid)\n                                print('Response: %s' % response)\n\n                        return response\n\n                oprice = order.price\n\n                # does the LIM price cross the spread?\n\n                if order.otype == 'Bid':\n                        if len(self.asks.lob) > 0 and oprice >= self.asks.lob[0][0]:\n                                # crosses: this LIM bid lifts the best ask, so treat as IOC\n                                if verbose: print(\"Bid LIM $%s lifts best ask ($%s) =>IOC\" % (oprice, self.asks.lob[0][0]))\n                                order.ostyle = 'IOC'\n                                response = self.process_order_take(time, order, verbose)\n                        else:\n                                response = process_LIM(order, verbose)\n\n                elif order.otype == 'Ask':\n                        if len(self.bids.lob) > 0 and oprice <= self.bids.lob[0][0]:\n                                # crosses: this LIM ask hits the best bid, so treat as IOC\n                                if verbose: print(\"Ask LIM $%s hits best bid ($%s) =>IOC\" % (oprice, self.bids.lob[0][0]))\n                                order.ostyle = 'IOC'\n                                response = self.process_order_take(time, order, verbose)\n                        else:\n                                response = process_LIM(order, verbose)\n                else:\n                        # we should never get here\n                        sys.exit('process_order_LIM() given neither Bid nor Ask')\n\n                return response\n\n\n        def process_order_pending(self, time, order, verbose):\n                # this returns a null response because it just places the order on the relevant pending-execution list\n                # order styles LOO and MOO are subsequently processed/executed in the market_open() method\n                # order styles LOC and MOC are subsequently processed/executed in the market_close() method\n\n                if order.ostyle == 'LOO' or order.ostyle == 'MOO':\n                        if order.otype == 'Bid':\n                                self.bids.on_open.append(order)\n                        elif order.otype == 'Ask':\n                                self.asks.on_open.append(order)\n                        else:\n                                # we should never get here\n                                sys.exit('process_order_pending() LOO/MOO given neither Bid nor Ask')\n\n                elif order.ostyle == 'LOC' or order.ostyle == 'MOC':\n                        if order.otype == 'Bid':\n                                self.bids.on_close.append(order)\n                        elif order.otype == 'Ask':\n                                self.asks.on_close.append(order)\n                        else:\n                                # we should never get here\n                                sys.exit('process_order_pending() LOC/MOC given neither Bid nor Ask')\n\n                else: sys.exit('process_order_pending() given something other than LOO MOO LOC MOC')\n\n                return {'TraderMsgs':None, 'TapeEvents':None}\n\n\n\n# Exchange's internal orderbooks\n\nclass Exchange(Orderbook):\n\n\n        def __init__(self, eid):\n                self.eid = eid          # exchange ID string\n                self.lit = Orderbook(eid + \"Lit\")  # traditional lit exchange\n                self.drk = Orderbook(eid + \"Drk\")  # NB just a placeholder -- in this version of BSE the dark pool is undefined\n                self.tape = []          # tape: consolidated record of trading events on the exchange\n                self.trader_recs = {}   # trader records (balances from fees, reputations, etc), indexed by traderID\n                self.order_id = 0       # unique ID code for each order received by the exchange, starts at zero\n                self.open = False       # is the exchange open (for business) or closed?\n\n\n        def __str__(self):\n                s = '\\nExchID: %s ' % (self.eid)\n                if self.open: s = s + '(Open)\\n'\n                else: s = s + '(Closed)\\n'\n                s = s + 'Lit ' + str(self.lit)\n                s = s + 'Dark ' + str(self.drk)\n                s = s + 'OID: %d; ' % self.order_id\n                s = s + 'TraderRecs: %s' % self.trader_recs\n                s = s + 'Tape[-4:]: %s' % self.tape[-4:]\n                s = s + '\\n'\n                return s\n\n\n        class trader_record:\n                # exchange's records for an individual trader\n\n                def __init__(self, time, tid):\n                        self.tid = tid          # this trader's ID\n                        self.regtime = time     # time when first registered\n                        self.balance = 0        # balance at the exchange (from exchange fees and rebates)\n                        self.reputation = None  # reputation -- FOR GEORGE CHURCH todo -- integrate with George's work\n                        self.orders = []        # list of orders received from this trader\n                        self.msgs = []          # list of messages sent to this trader\n\n\n                def __str__(self):\n                        s = '[%s bal=%d rep=%s orders=%s msgs=%s]' % (self.tid, self.balance, self.reputation, self.orders, self.msgs)\n                        return s\n\n\n        def consolidate_responses(self, responses):\n\n                consolidated = {'TraderMsgs':[], 'TapeEvents':[]}\n\n                if len(responses) > 1:\n                        # only need to do this if been given more than one response\n                        for resp in responses:\n                                consolidated['TraderMsgs'].append(resp['TraderMsgs'])\n                                consolidated['TapeEvents'].append(resp['TapeEvents'])\n                        # could sort into time-order here, but its not essential -- todo\n                else:\n                        consolidated = responses[0]\n\n                return consolidated\n\n\n        def mkt_open(self, time, verbose):\n\n                # exchange opens for business\n                # need to process any LOO and MOO orders:\n                # processes LOO and MOO orders in sequence wrt where they are in the relevant on_open list\n\n                def open_pool(time, pool, verbose):\n\n                        responses = []\n\n                        # LOO and MOO\n                        for order in pool.on_open:\n                                if order.ostyle == 'LIM':\n                                        responses.append(pool.process_order_LIM(time, order, verbose))\n                                elif order.ostyle == 'MKT':\n                                        responses.append(pool.process_order_take(time, order, verbose))\n                                else: sys.exit('FAIL in open_pool(): neither LIM nor MKT in on_open list ')\n\n                        return responses\n\n\n                print('Exchange %s opening for business', self.eid)\n                response_l = open_pool(self.lit)\n                response_d = open_pool(self.drk)\n\n                self.open = True\n                return consolidate_responses([response_l, response_d])\n\n\n        def mkt_close(self):\n\n                # exchange closes for business\n                # need to process any LOC, MOC, and GFD orders\n                # NB GFD orders assumes that exchange closing is the same as end of day\n\n                def close_pool(time, pool, verbose):\n\n                        responses = []\n\n                        # LOC and MOC\n                        for order in pool.on_close:\n                                if order.ostyle == 'LIM':\n                                        responses.append(pool.process_order_LIM(time, order, verbose))\n                                elif order.ostyle == 'MKT':\n                                        responses.append(pool.process_order_take(time, order, verbose))\n                                else: sys.exit('FAIL in open_pool(): neither LIM nor MKT in on_close list ')\n                        # GFD  -- cancel any orders still on the books\n                        for order in pool.orders:\n                                if order.ostyle == 'GFD':\n                                        responses.append(pool.process_order_CAN(time, order, verbose))\n\n                        return responses\n\n                print('Exchange %s closing for business', self.eid)\n                response_l = close_pool(self.lit)\n                response_d = close_pool(self.drk)\n\n                self.open = False\n                return consolidate_responses([response_l, response_d])\n\n\n        def tape_update(self, tr, verbose):\n\n                # updates the tape\n                if verbose: print(\"Tape update: tr=%s; len(tape)=%d tape[-3:]=%s\" % (tr, len(self.tape), self.tape[-3:]))\n\n                self.tape.append(tr)\n\n                if tr['type'] == 'Trade':\n                        # process the trade\n                        if verbose: print('>>>>>>>>TRADE t=%5.3f $%d Q%d %s %s\\n' %\n                                          (tr['time'], tr['price'], tr['qty'], tr['party1'], tr['party2']))\n                        self.last_trans_t = tr['time']  # time of last transaction\n                        self.last_trans_p = tr['price']  # price of last transaction\n                        self.last_trans_q = tr['qty']  # quantity of last transaction\n                        return tr\n\n\n        def dump_tape(self, session_id, dumpfile, tmode,traders):\n\n                # print('Dumping tape s.tape=')\n                # for ti in self.tape:\n                #         print('%s' % ti)\n\n                for tapeitem in self.tape:\n                        # print('tape_dump: tapitem=%s' % tapeitem)\n                        if tapeitem['type'] == 'Trade':\n                                dumpfile.write('%s, %s, %s,%s,%s,%s,%s, %s\\n' % (session_id, tapeitem['pool_id'], tapeitem['time'], tapeitem['price'],tapeitem['qty'],traders[tapeitem['party2']].ttype, traders[tapeitem['party1']].ttype,str(tapeitem)))\n\n                if tmode == 'wipe':\n                        self.tape = []\n\n                aaFile = open('myFile_AA.csv','a');\n\n                for tapeitem in self.tape:\n                        # print('tape_dump: tapitem=%s' % tapeitem)\n                        if tapeitem['type'] == 'Trade':\n                                if(traders[tapeitem['party2']].ttype == 'SHVR' and traders[tapeitem['party1']].ttype == 'AA'):\n                                        aaFile.write('%s\\n' % (tapeitem['price']))\n\n                aaFile.close()\n\n                iaaFile = open('myFile_IAA.csv','a')\n\n                for tapeitem in self.tape:\n                        # print('tape_dump: tapitem=%s' % tapeitem)\n                        if tapeitem['type'] == 'Trade':\n                                if (traders[tapeitem['party2']].ttype == 'SHVR' and traders[tapeitem['party1']].ttype == 'IAA'):\n                                        iaaFile.write('%s\\n' % (tapeitem['price']))\n\n                iaaFile.close()\n\n\n\n\n\n        def process_order(self, time, order, verbose):\n                # process the order passed in as a parameter\n                # number of allowable order-types is significantly expanded in BSE2 (previously just had LIM/MKT functionality)\n                # BSE2 added order types such as FOK, ICE, etc\n                # also added stub logic for larger orders to be routed to dark pool\n                # currently treats dark pool as another instance of Orderbook, same as lit pool\n                # incoming order has order ID assigned by exchange\n                # return is {'tape_summary':... ,'trader_msgs':...}, explained further below\n\n                if verbose: print('>Exchange.process_order()\\n')\n\n                trader_id = order.tid\n\n                if not trader_id in self.trader_recs:\n                        # we've not seen this trader before, so create a record for it\n                        if verbose: print('t=%f: Exchange %s registering Trader %s:' % (time, self.eid, trader_id))\n                        trader_rec = self.trader_record(time, trader_id)\n                        self.trader_recs[trader_id] = trader_rec\n                        if verbose: print('record= %s' % str(trader_rec))\n\n                # what quantity qualifies as a block trade (route to DARK)?\n                block_size = 300\n\n                ostyle = order.ostyle\n\n                ack_response = Exch_msg(trader_id, order.orderid, 'ACK', [[order.price, order.qty]],  None, 0, 0)\n                if verbose: print ack_response\n\n\n                # which pool does it get sent to: Lit or Dark?\n                if order.qty < block_size:\n                        if verbose: print('Process_order: qty=%d routes to LIT pool' % order.qty)\n                        pool = self.lit\n                else:\n                        if verbose: print('Process_order: qty=%d routes to DARK pool' % order.qty)\n                        pool = self.drk\n\n\n                # Cancellations don't generate new order-ids\n\n                if ostyle == 'CAN':\n                        # deleting a single existing order\n                        # NB this trusts the order.qty -- sends CANcel only to the pool that the QTY indicates\n                        response = pool.process_order_CAN(time, order, verbose)\n\n                elif ostyle == 'XXX':\n                        # delete all orders from the trader that issued the XXX order\n                        # need to sweep through both pools\n                        response_l = self.lit.process_order_XXX(time, order, verbose)\n                        response_d = self.drk.process_order_XXX(time, order, verbose)\n                        # the response from either lit and/or dark might be a string of responses from multiple individual CAN orders\n                        # here we just glue those together for later processing\n                        self.consolidate_responses([response_l, response_d])\n\n                else:\n                        # give each new order a unique ID\n                        order.orderid = self.order_id\n                        self.order_id = order.orderid + 1\n\n                        ack_msg = Exch_msg(trader_id, order.orderid, 'ACK', [[order.price, order.qty]], None, 0, 0)\n\n                        if verbose: print('OrderID:%d, ack:%s\\n' % (order.orderid, ack_msg))\n\n                        if ostyle == 'LIM' or ostyle == 'GFD':\n                                # GFD is just a LIM order with an expiry time\n                                response = pool.process_order_LIM(time, order, verbose)\n\n                        elif ostyle == 'MKT' or ostyle == 'AON' or ostyle == 'FOK' or ostyle == 'IOC':\n                                if ostyle == 'AON': pool.resting.append(order) # put it on the list of resting orders\n                                response = pool.process_order_take(time, order, verbose)\n                                # AON is a special case: if current response is that it FAILed, but has not timed out\n                                #                        then ignore the failure\n                                # and if it didn't fail, check to remove it from the MOB\n                                if ostyle == 'AON':\n                                        if response['TraderMsgs'].event == 'FAIL':\n                                                # it failed, but has it timed out yet?\n                                                if time < order.styleparams['ExpiryTime']:\n                                                        # it hasn't expired yet\n                                                        # nothing to say back to the trader, nothing to write to tape\n                                                        response['TraderMsgs'] = None\n                                                        response['TapeEvents'] = None\n                                        else:   # AON order executed successfully, remove it from the MOB\n                                                pool.resting.remove(order)\n\n                        elif ostyle == 'LOC' or ostyle == 'MOC' or ostyle == 'LOO' or ostyle == 'MOO':\n                                # these are just placed on the relevant wait-list at the exchange\n                                # and then processed by mkt_open() or mkt_close()\n                                response = pool.process_order_pending(time, order, verbose)\n\n                        elif ostyle == 'OCO' or ostyle == 'OSO':\n                                # processing of OSO and OCO orders is a recursive call of this method\n                                # that is, call process_order() on the first order in the OXO pair\n                                # then call or ignore the second order depending on outcome of the first\n                                # OCO and OSO are both defined via the following syntax...\n                                # ostyle=OSO or OCO; styleparams=[[order1], [order2]]\n                                # currently only defined for [order1] and [order2] both LIM type\n\n                                if len(order.styleparams) == 2:\n                                        order1 = order.styleparams[0]\n                                        order2 = order.styleparams[1]\n                                        if order1.ostyle == 'LIM' and order2.ostyle == 'LIM':\n                                                sys.exit('Give up')\n\n                                response = pool.process_order_OXO(time, order, verbose)\n\n                        elif ostyle == 'ICE':\n                                # this boils down to a chain of successively refreshed OSO orders, until its all used up\n                                # so underneath it's LIM functionality only\n                                response = pool.process_order_ICE(time, order, verbose)\n\n                        else:\n                                sys.exit('FAIL: process_order given order style %s', ostyle)\n\n\n\n\n                if verbose: print ('<Exch.Proc.Order(): Order=%s; Response=%s' % (order, response))\n\n                # default return values\n                trader_msgs = None\n                tape_events = None\n\n                if response != None:\n                        # non-null response should be dictionary with two items: list of trader messages and list of tape events\n                        if verbose: print('Response ---- ')\n                        trader_msgs = response[\"TraderMsgs\"]\n                        tape_events = response[\"TapeEvents\"]\n\n                        total_fees = 0\n                        # trader messages include details of fees charged by exchange for processing this order\n                        for msg in trader_msgs:\n                                if msg.tid == trader_id:\n                                        total_fees += msg.fee\n                                        if verbose: print('Trader %s adding fee %d from msg %s' % (trader_id, msg.fee, msg))\n                        self.trader_recs[trader_id].balance += total_fees\n                        if verbose: print('Trader %s Exch %s: updated balance=%d' % (trader_id, self.eid, self.trader_recs[trader_id].balance))\n\n                        # record the tape events on the tape\n                        if len(tape_events) > 0:\n                                for event in tape_events:\n                                        self.tape_update(event, verbose)\n\n                        if verbose:\n                                print('<Exch.Proc.Order(): tape_events=%s' % tape_events)\n                                s = '<Exch.Proc.Order(): trader_msgs=['\n                                for msg in trader_msgs:\n                                        s = s + '[' + str(msg) + '], '\n                                s = s + ']'\n                                print(s)\n\n                        # by this point, tape has been updated\n                        # so in principle only thing process_order hands back to calling level is messages for traders\n\n                        # but...\n\n                        # for back-compatibility with this method in BSE1.x and with trader definitions (AA, ZIP, etc)\n                        # we ALSO hand back a \"transaction record\" which summarises any actual transactions\n                        # or is None if no transactions occurred. Structure was:\n                        # transaction_record = {'type': 'Trade',\n                        #                       'time': time,\n                        #                       'price': price,\n                        #                       'party1': counterparty,\n                        #                       'party2': order.tid,\n                        #                       'qty': order.qty\n                        #                       }\n                        # In BSE 1.x the maximum order-size was Qty=1, which kept things very simple\n                        # In BSE 2.x, a single order of Qty>1 can result in multiple separate transactions,\n                        # so we need to aggregate those into one order. Do this by computing total cost C of\n                        # execution for quantity Q and then declaring that the price for each unit was C/Q\n                        # As there may now be more then one counterparty to a single order, party1 & party2 returned as None\n\n                        tape_summary = None\n                        if len(tape_events) > 0:\n                                total_cost = 0\n                                total_qty = 0\n                                if verbose: print('tape_summary:')\n                                for event in tape_events:\n                                        if event['type'] == 'Trade':\n                                                total_cost += event['price']\n                                                total_qty += event['qty']\n                                                if verbose: print('total_cost=%d; total_qty=%d' % (total_cost, total_qty))\n                                if total_qty > 0 :\n                                        avg_cost = total_cost / total_qty\n                                        if verbose: print('avg_cost=%d' % avg_cost)\n                                        tape_summary = {'type': 'Trade',\n                                                        'time': time,\n                                                        'price': avg_cost,\n                                                        'party1': None,\n                                                        'party2': None,\n                                                        'qty': total_qty}\n\n                        return {'tape_summary':tape_summary, 'trader_msgs':trader_msgs}\n                else: return {'tape_summary':None, 'trader_msgs':None}\n\n\n        # this returns the LOB data \"published\" by the exchange,\n        # only applies to the lit book -- dark pools aren't published\n        def publish_lob(self, time, tape_depth, verbose):\n\n                n_bids = len(self.lit.bids.orders)\n                if n_bids > 0 :\n                        best_bid_p = self.lit.bids.lob_anon[0][0]\n                else:   best_bid_p = None\n\n                n_asks = len(self.lit.asks.orders)\n                if n_asks > 0:\n                        best_ask_p = self.lit.asks.lob_anon[0][0]\n                else:\n                        best_ask_p = None\n\n                public_data = {}\n                public_data['time'] = time\n                public_data['bids'] = {'bestp':best_bid_p,\n                                     'worstp':self.lit.bids.worst_price,\n                                     'n': n_bids,\n                                     'lob':self.lit.bids.lob_anon}\n                public_data['asks'] = {'bestp':best_ask_p,\n                                     'worstp':self.lit.asks.worst_price,\n                                     'n': n_asks,\n                                     'lob':self.lit.asks.lob_anon}\n\n                public_data['last_t'] = self.lit.last_trans_t\n                public_data['last_p'] = self.lit.last_trans_p\n                public_data['last_q'] = self.lit.last_trans_q\n\n\n\n\n                if tape_depth == None :\n                        public_data['tape'] = self.tape                 # the full thing\n                else:\n                        public_data['tape'] = self.tape[-tape_depth:]   # depth-limited\n\n                public_data['midprice'] = None\n                public_data['microprice'] = None\n                if n_bids>0 and n_asks>0 :\n                        # neither side of the LOB is empty\n                        best_bid_q= self.lit.bids.lob_anon[0][1]\n                        best_ask_q = self.lit.asks.lob_anon[0][1]\n                        public_data['midprice'] = self.lit.midprice(best_bid_p, best_bid_q, best_ask_p, best_ask_q)\n                        public_data['microprice'] = self.lit.microprice(best_bid_p, best_bid_q, best_ask_p, best_ask_q)\n\n                if verbose:\n                        print('Exchange.publish_lob: t=%s' % time)\n                        print('BID_lob=%s' % public_data['bids']['lob'])\n                        print('best=%s; worst=%s; n=%s ' % (best_bid_p, self.lit.bids.worst_price, n_bids))\n                        print(str(self.lit.bids))\n                        print('ASK_lob=%s' % public_data['asks']['lob'])\n                        print('best=%s; worst=%s; n=%s ' % (best_ask_p, self.lit.asks.worst_price, n_asks))\n                        print(str(self.lit.asks))\n                        print('Midprice=%s; Microprice=%s' % (public_data['midprice'], public_data['microprice']))\n                        print('Last transaction: time=%s; price=%s; qty=%s' % (public_data['last_t'],public_data['last_p'],public_data['last_q']))\n                        print('tape[-3:]=%s'% public_data['tape'][-3:])\n                        sys.stdout.flush()\n\n\n                return public_data\n\n\n\n\n\n\n\n##########################---Below lies the experiment/test-rig---##################\n\n\n\n# trade_stats()\n# dump CSV statistics on exchange data and trader population to file for later analysis\n# this makes no assumptions about the number of types of traders, or\n# the number of traders of any one type -- allows either/both to change\n# between successive calls, but that does make it inefficient as it has to\n# re-analyse the entire set of traders on each call\ndef trade_stats(expid, traders, dumpfile, time, lob):\n        trader_types = {}\n        n_traders = len(traders)\n        for t in traders:\n                ttype = traders[t].ttype\n                if ttype in trader_types.keys():\n                        t_balance = trader_types[ttype]['balance_sum'] + traders[t].balance\n                        n = trader_types[ttype]['n'] + 1\n                else:\n                        t_balance = traders[t].balance\n                        n = 1\n                trader_types[ttype] = {'n':n, 'balance_sum':t_balance}\n\n\n        dumpfile.write('%s, %06d, ' % (expid, time))\n        for ttype in sorted(list(trader_types.keys())):\n                n = trader_types[ttype]['n']\n                s = trader_types[ttype]['balance_sum']\n                dumpfile.write('%s, %d, %d, %f, ' % (ttype, s, n, s / float(n)))\n\n        if lob['bids']['bestp'] != None :\n                dumpfile.write('%d, ' % (lob['bids']['bestp']))\n        else:\n                dumpfile.write('N, ')\n        if lob['asks']['bestp'] != None :\n                dumpfile.write('%d, ' % (lob['asks']['bestp']))\n        else:\n                dumpfile.write('N, ')\n        dumpfile.write('\\n');\n\n\n\n# create a bunch of traders from traders_spec\n# returns tuple (n_buyers, n_sellers)\n# optionally shuffles the pack of buyers and the pack of sellers\ndef populate_market(traders_spec, traders, shuffle, verbose):\n\n\n        def trader_type(robottype, name):\n                if robottype == 'GVWY':\n                        return Trader_Giveaway('GVWY', name, 0.00, 0)\n                elif robottype == 'ZIC':\n                        return Trader_ZIC('ZIC', name, 0.00, 0)\n                elif robottype == 'SHVR':\n                        return Trader_Shaver('SHVR', name, 0.00, 0)\n                elif robottype == 'ISHV':\n                        return Trader_ISHV('ISHV', name, 0.00, 0)\n                elif robottype == 'SNPR':\n                        return Trader_Sniper('SNPR', name, 0.00, 0)\n                elif robottype == 'ZIP':\n                        return Trader_ZIP('ZIP', name, 0.00, 0)\n                elif robottype == 'AA':\n                        return Trader_AA('AA', name, 0.00, 0)\n\n                elif robottype == 'AAA':\n                        return Trader_AA('AAA', name, 0.00, 0)\n\n\n                elif robottype == 'SIMPLE':\n                        return Trader_Simple_MLOFI('SIMPLE',name,0.00,0)\n                elif robottype == 'IAA_MLOFI_ASK':\n                        return Trader_IAA_MLOFI('MLOFI_ASK',name,0.00,0)\n                elif robottype == 'IAA_MLOFI_BID':\n                        return Trader_IAA_MLOFI('MLOFI_BID',name,0.00,0)\n                elif robottype == 'AAAA':\n                        return Trader_AA('AAAA', name, 0.00, 0)\n\n                elif robottype == 'ISHV_ASK':\n                        return Trader_ISHV('ISHV_ASK', name, 0.00, 0)\n                elif robottype == 'GDX':\n                        return Trader_GDX('GDX', name, 0.00, 0)\n                elif robottype == 'GDXB':\n                        return Trader_GDX('GDXB', name, 0.00, 0)\n                elif robottype == 'ZIPP':\n                        return Trader_ZIP('ZIPP', name, 0.00, 0)\n\n                elif robottype == 'IAA_MLOFI':\n                        return Trader_IAA_MLOFI('MLOFI',name,0.00,0,3)\n                elif robottype == 'IAA_MLOFI1':\n                        return Trader_IAA_MLOFI('MLOFI1',name,0.00,0, 1)\n\n                elif robottype == 'IAA_MLOFI2':\n                        return Trader_IAA_MLOFI('MLOFI2', name, 0.00,0, 2)\n                elif robottype == 'IAA_MLOFI3':\n                        return Trader_IAA_MLOFI('MLOFI3', name, 0.00,0, 3)\n                elif robottype == 'IAA_MLOFI4':\n                        return Trader_IAA_MLOFI('MLOFI4', name, 0.00, 0,4)\n                elif robottype == 'IAA_MLOFI5':\n                        return Trader_IAA_MLOFI('MLOFI5', name, 0.00,0, 5)\n                elif robottype == 'IAA_MLOFI6':\n                        return Trader_IAA_MLOFI('MLOFI6', name, 0.00,0, 6)\n                elif robottype == 'IAA_MLOFI7':\n                        return Trader_IAA_MLOFI('MLOFI7', name, 0.00,0, 7)\n                elif robottype == 'IAA_MLOFI8':\n                        return Trader_IAA_MLOFI('MLOFI8', name, 0.00,0, 8)\n                elif robottype == 'IAA_MLOFI9':\n                        return Trader_IAA_MLOFI('MLOFI9', name, 0.00,0, 9)\n                elif robottype == 'IAA_MLOFI10':\n                        return Trader_IAA_MLOFI('MLOFI10', name, 0.00, 0, 10)\n                elif robottype == 'IAA_MLOFI11':\n                        return Trader_IAA_MLOFI('MLOFI11', name, 0.00, 0, 11)\n                elif robottype == 'IAA_MLOFI12':\n                        return Trader_IAA_MLOFI('MLOFI12', name, 0.00, 0, 12)\n                elif robottype == 'IAA_MLOFI13':\n                        return Trader_IAA_MLOFI('MLOFI13', name, 0.00, 0, 13)\n                elif robottype == 'IAA_MLOFI14':\n                        return Trader_IAA_MLOFI('MLOFI14', name, 0.00, 0, 14)\n                elif robottype == 'IAA_MLOFI15':\n                        return Trader_IAA_MLOFI('MLOFI15', name, 0.00, 0, 15)\n                elif robottype == 'IAA_MLOFI16':\n                        return Trader_IAA_MLOFI('MLOFI16', name, 0.00, 0, 16)\n                elif robottype == 'IAA_MLOFI17':\n                        return Trader_IAA_MLOFI('MLOFI17', name, 0.00, 0, 17)\n                elif robottype == 'IAA_MLOFI18':\n                        return Trader_IAA_MLOFI('MLOFI18', name, 0.00, 0, 18)\n                elif robottype == 'IAA_MLOFI19':\n                        return Trader_IAA_MLOFI('MLOFI19', name, 0.00, 0, 19)\n                elif robottype == 'IAA_MLOFI20':\n                        return Trader_IAA_MLOFI('MLOFI20', name, 0.00, 0, 20)\n                elif robottype == 'IAA_MLOFI30':\n                        return Trader_IAA_MLOFI('MLOFI30', name, 0.00, 0, 30)\n                elif robottype == 'IAA_MLOFI50':\n                        return Trader_IAA_MLOFI('MLOFI50', name, 0.00, 0, 50)\n                elif robottype == 'IZIP_3':\n                        return Trader_IZIP_MLOFI('IZIP_3',name,0.00,0,3)\n\n                elif robottype == 'IGDX_3':\n                        return Trader_IGDX_MLOFI('IGDX_3', name, 0.00, 0, 3)\n                elif robottype == 'IZIPB_3':\n                        return Trader_IZIP_MLOFI('IZIPB_3',name,0.00,0,3)\n\n                elif robottype == 'IGDXB_3':\n                        return Trader_IGDX_MLOFI('IGDXB_3', name, 0.00, 0, 3)\n                elif robottype == 'IAAB_3':\n                        return Trader_IAA_MLOFI('IAAB3', name, 0.00,0, 3)\n\n\n                elif robottype == 'ASK_IGDX_3':\n                        return Trader_IGDX_MLOFI('ASK_IGDX_3', name, 0.00, 0, 3)\n                elif robottype == 'BID_IGDX_3':\n                        return Trader_IGDX_MLOFI('BID_IGDX_3', name, 0.00, 0, 3)\n                elif robottype == 'ASK_IZIP_3':\n                        return Trader_IZIP_MLOFI('ASK_IZIP_3',name,0.00,0,3)\n                elif robottype == 'BID_IZIP_3':\n                        return Trader_IZIP_MLOFI('BID_IZIP_3',name,0.00,0,3)\n                elif robottype == 'ASK_IAA_3':\n                        return Trader_IAA_MLOFI('ASK_IAA_3', name, 0.00,0, 3)\n                elif robottype == 'BID_IAA_3':\n                        return Trader_IAA_MLOFI('BID_IAA_3', name, 0.00, 0, 3)\n\n                elif robottype == 'ASK_AA':\n                        return Trader_AA('ASK_AA', name, 0.00, 0)\n                elif robottype == 'BID_AA':\n                        return Trader_AA('BID_AA', name, 0.00, 0)\n                elif robottype == 'ASK_GDX':\n                        return Trader_GDX('ASK_GDX', name, 0.00, 0)\n                elif robottype == 'BID_GDX':\n                        return Trader_GDX('BID_GDX', name, 0.00, 0)\n                elif robottype == 'ASK_ZIP':\n                        return Trader_ZIP('ASK_ZIP', name, 0.00, 0)\n                elif robottype == 'BID_ZIP':\n                        return Trader_ZIP('BID_ZIP', name, 0.00, 0)\n\n\n                elif robottype == 'IAA':\n                        return Trader_IAA_MLOFI('IAA', name, 0.00,0, 3)\n                elif robottype == 'IAA_3':\n                        return Trader_IAA_MLOFI('IAA_3', name, 0.00,0, 3)\n\n\n                elif robottype == 'ASK_SHVR':\n                        return Trader_Shaver('ASK_SHVR', name, 0.00, 0)\n                elif robottype == 'BID_SHVR':\n                        return Trader_Shaver('BID_SHVR', name, 0.00, 0)\n                elif robottype == 'ASK_ISHV_3':\n                        return Trader_ISHV('ASK_ISHV_3', name, 0.00, 0)\n                elif robottype == 'BID_ISHV_3':\n                        return Trader_ISHV('BID_ISHV_3', name, 0.00, 0)\n\n\n                elif robottype == 'GDXXX':\n                        return Trader_GDX('GDXXX', name, 0.00, 0)\n                elif robottype == 'GDXX':\n                        return Trader_GDX('GDXX', name, 0.00, 0)\n\n\n\n                elif robottype == 'IAA_NEW':\n                        return Trader_IAA_NEW('IAA_NEW', name, 0.00, 0, 3)\n\n\n                elif robottype == 'ZZISHV':\n                        return Trader_ZZISHV('ZZISHV', name, 0.00, 0,3)\n                elif robottype == 'ASK_ZZISHV':\n                        return Trader_ZZISHV('ASK_ZZISHV', name, 0.00, 0,3)\n                elif robottype == 'BID_ZZISHV':\n                        return Trader_ZZISHV('BID_ZZISHV', name, 0.00, 0,3)\n                elif robottype == 'ASK_ISHV':\n                        return Trader_ISHV('ASK_ISHV', name, 0.00, 0)\n                elif robottype == 'BID_ISHV':\n                        return Trader_ISHV('BID_ISHV', name, 0.00, 0)\n\n                elif robottype == 'ZIPPP':\n                        return Trader_ZIP('ZIPPP', name, 0.00, 0)\n                elif robottype == 'ZIPP':\n                        return Trader_ZIP('ZIPP', name, 0.00, 0)\n                elif robottype == 'IZIP':\n                        return Trader_IZIP_MLOFI('IZIP',name,0.00,0,3)\n                elif robottype == 'IGDX':\n                        return Trader_IGDX_MLOFI('IGDX', name, 0.00, 0, 3)\n\n\n                else:\n                        sys.exit('FATAL: don\\'t know robot type %s\\n' % robottype)\n\n\n\n        def shuffle_traders(ttype_char, n, traders):\n                for swap in range(n):\n                        t1 = (n - 1) - swap\n                        t2 = random.randint(0, t1)\n                        t1name = '%c%02d' % (ttype_char, t1)\n                        t2name = '%c%02d' % (ttype_char, t2)\n                        traders[t1name].tid = t2name\n                        traders[t2name].tid = t1name\n                        temp = traders[t1name]\n                        traders[t1name] = traders[t2name]\n                        traders[t2name] = temp\n\n\n        n_buyers = 0\n        for bs in traders_spec['buyers']:\n                ttype = bs[0]\n                for b in range(bs[1]):\n                        tname = 'B%02d' % n_buyers  # buyer i.d. string\n                        traders[tname] = trader_type(ttype, tname)\n                        n_buyers = n_buyers + 1\n\n        if n_buyers < 1:\n                sys.exit('FATAL: no buyers specified\\n')\n\n        if shuffle: shuffle_traders('B', n_buyers, traders)\n\n\n        n_sellers = 0\n        for ss in traders_spec['sellers']:\n                ttype = ss[0]\n                for s in range(ss[1]):\n                        tname = 'S%02d' % n_sellers  # buyer i.d. string\n                        traders[tname] = trader_type(ttype, tname)\n                        n_sellers = n_sellers + 1\n\n        if n_sellers < 1:\n                sys.exit('FATAL: no sellers specified\\n')\n\n        if shuffle: shuffle_traders('S', n_sellers, traders)\n\n        if verbose:\n                for t in range(n_buyers):\n                        bname = 'B%02d' % t\n                        print(traders[bname])\n                for t in range(n_sellers):\n                        bname = 'S%02d' % t\n                        print(traders[bname])\n\n\n        return {'n_buyers':n_buyers, 'n_sellers':n_sellers}\n\n\n\n# customer_orders(): allocate orders to traders\n# this version only issues LIM orders; LIM that crosses the spread executes as MKT\n# parameter \"os\" is order schedule\n# os['timemode'] is either 'periodic', 'drip-fixed', 'drip-jitter', or 'drip-poisson'\n# os['interval'] is number of seconds for a full cycle of replenishment\n# drip-poisson sequences will be normalised to ensure time of last replenishment <= interval\n# parameter \"pending\" is the list of future orders (if this is empty, generates a new one from os)\n# revised \"pending\" is the returned value\n#\n# also returns a list of \"cancellations\": trader-ids for those traders who are now working a new order and hence\n# need to kill quotes already on LOB from working previous order\n#\n#\n# if a supply or demand schedule mode is \"random\" and more than one range is supplied in ranges[],\n# then each time a price is generated one of the ranges is chosen equiprobably and\n# the price is then generated uniform-randomly from that range\n#\n# if len(range)==2, interpreted as min and max values on the schedule, specifying linear supply/demand curve\n# if len(range)==3, first two vals are min & max, third value should be a function that generates a dynamic price offset\n#                   -- the offset value applies equally to the min & max, so gradient of linear sup/dem curve doesn't vary\n# if len(range)==4, the third value is function that gives dynamic offset for schedule min,\n#                   and fourth is a function giving dynamic offset for schedule max, so gradient of sup/dem linear curve can vary\n#\n# the interface on this is a bit of a mess... could do with refactoring\n\n\ndef customer_orders(time, last_update, traders, trader_stats, os, pending, base_oid, verbose):\n\n\n        def sysmin_check(price):\n                if price < bse_sys_minprice:\n                        print('WARNING: price < bse_sys_min -- clipped')\n                        price = bse_sys_minprice\n                return price\n\n\n        def sysmax_check(price):\n                if price > bse_sys_maxprice:\n                        print('WARNING: price > bse_sys_max -- clipped')\n\n                        price = bse_sys_maxprice\n                return price\n        \n\n        def getorderprice(i, sched_end, sched, n, mode, issuetime):\n                # does the first schedule range include optional dynamic offset function(s)?\n                if len(sched[0]) > 2:\n                        offsetfn = sched[0][2][0]\n                        offsetfn_params = [sched_end] + [p for p in sched[0][2][1] ]\n                        if callable(offsetfn):\n                                # same offset for min and max\n                                offset_min = offsetfn(issuetime, offsetfn_params)\n                                offset_max = offset_min\n                        else:\n                                sys.exit('FAIL: 3rd argument of sched in getorderprice() should be [callable_fn [params]]')\n                        if len(sched[0]) > 3:\n                                # if second offset function is specfied, that applies only to the max value\n                                offsetfn = sched[0][3][0]\n                                offsetfn_params = [sched_end] + [p for p in sched[0][3][1] ]\n                                if callable(offsetfn):\n                                        # this function applies to max\n                                        offset_max = offsetfn(issuetime, offsetfn_params)\n                                else:\n                                        sys.exit('FAIL: 4th argument of sched in getorderprice() should be [callable_fn [params]]')\n                else:\n                        offset_min = 0.0\n                        offset_max = 0.0\n\n                pmin = sysmin_check(offset_min + min(sched[0][0], sched[0][1]))\n                pmax = sysmax_check(offset_max + max(sched[0][0], sched[0][1]))\n                prange = pmax - pmin\n                stepsize = prange / (n - 1)\n                halfstep = round(stepsize / 2.0)\n\n                if mode == 'fixed':\n                        orderprice = pmin + int(i * stepsize) \n                elif mode == 'jittered':\n                        orderprice = pmin + int(i * stepsize) + random.randint(-halfstep, halfstep)\n                elif mode == 'random':\n                        if len(sched) > 1:\n                                # more than one schedule: choose one equiprobably\n                                s = random.randint(0, len(sched) - 1)\n                                pmin = sysmin_check(min(sched[s][0], sched[s][1]))\n                                pmax = sysmax_check(max(sched[s][0], sched[s][1]))\n                        orderprice = random.randint(pmin, pmax)\n                else:\n                        sys.exit('FAIL: Unknown mode in schedule')\n                orderprice = sysmin_check(sysmax_check(orderprice))\n                return orderprice\n\n\n        def getissuetimes(n_traders, mode, interval, shuffle, fittointerval):\n                # generates a set of issue times for the customer orders to arrive at\n                interval = float(interval)\n                if n_traders < 1:\n                        sys.exit('FAIL: n_traders < 1 in getissuetime()')\n                elif n_traders == 1:\n                        tstep = interval\n                else:\n                        tstep = interval / (n_traders - 1)\n                arrtime = 0\n                issuetimes = []\n                for t in range(n_traders):\n                        if mode == 'periodic':\n                                arrtime = interval\n                        elif mode == 'drip-fixed':\n                                arrtime = t * tstep\n                        elif mode == 'drip-jitter':\n                                arrtime = t * tstep + tstep * random.random()\n                        elif mode == 'drip-poisson':\n                                # poisson requires a bit of extra work\n                                interarrivaltime = random.expovariate(n_traders / interval)\n                                arrtime += interarrivaltime\n                        else:\n                                sys.exit('FAIL: unknown time-mode in getissuetimes()')\n                        issuetimes.append(arrtime) \n                        \n                # at this point, arrtime is the *last* arrival time\n                if fittointerval and mode == 'drip-poisson' and (arrtime != interval) :\n                        # generated sum of interarrival times longer than the interval\n                        # squish them back so that last arrival falls at t=interval\n                        for t in range(n_traders):\n                                issuetimes[t] = interval * (issuetimes[t] / arrtime)\n\n                # optionally randomly shuffle the times\n                if shuffle:\n                        for t in range(n_traders):\n                                i = (n_traders - 1) - t\n                                j = random.randint(0, i)\n                                tmp = issuetimes[i]\n                                issuetimes[i] = issuetimes[j]\n                                issuetimes[j] = tmp\n                return issuetimes\n        \n\n        def getschedmode(time, os):\n                # os is order schedules\n                got_one = False\n                for sched in os:\n                        if (sched['from'] <= time) and (time < sched['to']) :\n                                # within the timezone for this schedule\n                                schedrange = sched['ranges']\n                                mode = sched['stepmode']\n                                sched_end_time = sched['to']\n                                got_one = True\n                                exit  # jump out the loop -- so the first matching timezone has priority over any others\n                if not got_one:\n                        sys.exit('Fail: time=%5.2f not within any timezone in os=%s' % (time, os))\n                return (schedrange, mode, sched_end_time)\n        \n\n        n_buyers = trader_stats['n_buyers']\n        n_sellers = trader_stats['n_sellers']\n\n        shuffle_times = True\n\n        cancellations = []\n\n        oid = base_oid\n\n        max_qty = 1\n\n        if len(pending) < 1:\n                # list of pending (to-be-issued) customer orders is empty, so generate a new one\n                new_pending = []\n\n                # demand side (buyers)\n                issuetimes = getissuetimes(n_buyers, os['timemode'], os['interval'], shuffle_times, True)\n                ordertype = 'Bid'\n                orderstyle = 'LIM'\n                (sched, mode, sched_end) = getschedmode(time, os['dem'])\n                for t in range(n_buyers):\n                        issuetime = time + issuetimes[t]\n                        tname = 'B%02d' % t\n                        ## flag\n                        orderprice = getorderprice(t, sched_end, sched, n_buyers, mode, issuetime)\n                        # if time<101 or (time>201 and time <301) or (time>401 and time<501):\n                        #         orderprice = 150\n                        # else:\n                        #         orderprice = 100\n                        orderqty = random.randint(1,max_qty)\n                        # order = Order(tname, ordertype, orderstyle, orderprice, orderqty, issuetime, None, oid)\n                        order = Assignment(\"CUS\", tname, ordertype, orderstyle, orderprice, orderqty, issuetime, None, oid)\n                        oid += 1\n                        new_pending.append(order)\n                        \n                # supply side (sellers)\n                issuetimes = getissuetimes(n_sellers, os['timemode'], os['interval'], shuffle_times, True)\n                ordertype = 'Ask'\n                orderstyle = 'LIM'\n                (sched, mode, sched_end) = getschedmode(time, os['sup'])\n                for t in range(n_sellers):\n                        issuetime = time + issuetimes[t]\n                        tname = 'S%02d' % t\n                        orderprice = getorderprice(t, sched_end, sched, n_sellers, mode, issuetime)\n                        # if time<101 or (time>201 and time <301) or (time>401 and time<501):\n                        #         orderprice = 50\n                        # else:\n                        #         orderprice = 20\n                        orderqty = random.randint(1, max_qty)\n                        # order = Order(tname, ordertype, orderstyle, orderprice, orderqty, issuetime, None, oid)\n                        order = Assignment(\"CUS\", tname, ordertype, orderstyle, orderprice, orderqty, issuetime, None, oid)\n                        oid += 1\n                        new_pending.append(order)\n        else:\n                # there are pending future orders: issue any whose timestamp is in the past\n                new_pending = []\n                for order in pending:\n                        if order.time < time:\n                                # this order should have been issued by now\n                                # issue it to the trader\n                                tname = order.trad_id\n                                response = traders[tname].add_cust_order(order, verbose)\n                                if verbose: print('Customer order: %s %s' % (response, order))\n                                if response == 'LOB_Cancel' :\n                                    cancellations.append(tname)\n                                    if verbose: print('Cancellations: %s' % (cancellations))\n                                # and then don't add it to new_pending (i.e., delete it)\n                        else:\n                                # this order stays on the pending list\n                                new_pending.append(order)\n        return [new_pending, cancellations, oid]\n\n\n\n# one session in the market\ndef market_session(sess_id, starttime, endtime, trader_spec, order_schedule, summaryfile, tapedumpfile, blotterdumpfile,\n                   dump_each_trade, verbose):\n\n        n_exchanges = 1\n\n        tape_depth = 5 # number of most-recent items from tail of tape to be published at any one time\n\n        verbosity = False\n\n        verbose = verbosity             # main loop verbosity\n        orders_verbose = verbosity\n        lob_verbose = False\n        process_verbose = False\n        respond_verbose = False\n        bookkeep_verbose = False\n\n        # fname = 'prices' + sess_id +'.csv'\n        # prices_data_file = open(fname, 'w')\n\n        # initialise the exchanges\n        exchanges = []\n        for e in range(n_exchanges):\n                eid = \"Exch%d\" % e\n                exch = Exchange(eid)\n                exchanges.append(exch)\n                if verbose: print('Exchange[%d] =%s' % (e, str(exchanges[e])))\n\n        # create a bunch of traders\n        traders = {}\n        trader_stats = populate_market(trader_spec, traders, True, verbose)\n\n\n        # print 'describe traders:'\n        # for tid in traders:\n        #         print 'trader.ttype: %s , trader.tid: %s' %(traders[tid].ttype,tid)\n\n\n        # timestep set so that can process all traders in one second\n        # NB minimum inter-arrival time of customer orders may be much less than this!!\n        timestep = 1.0 / float(trader_stats['n_buyers'] + trader_stats['n_sellers'])\n        \n        duration = float(endtime - starttime)\n\n        last_update = -1.0\n\n        time = starttime\n\n        next_order_id = 0\n\n        pending_cust_orders = []\n\n        if verbose: print('\\n%s;  ' % (sess_id))\n\n        tid = None\n\n        while time < endtime:\n\n                # how much time left, as a percentage?\n                time_left = (endtime - time) / duration\n                if verbose: print('\\n\\n%s; t=%08.2f (percent remaining: %4.1f/100) ' % (sess_id, time, time_left*100))\n\n                trade = None\n\n                # get any new assignments (customer orders) for traders to execute\n                # and also any customer orders that require previous orders to be killed\n                [pending_cust_orders, kills, noid] = customer_orders(time, last_update, traders, trader_stats,\n                                                                     order_schedule, pending_cust_orders, next_order_id, orders_verbose)\n\n                next_order_id = noid\n\n                if verbose:\n                        print('t:%f, noid=%d, pending_cust_orders:' % (time, noid))\n                        for order in pending_cust_orders: print('%s; ' % str(order))\n\n                # if any newly-issued customer orders mean quotes on the LOB need to be cancelled, kill them\n                if len(kills) > 0:\n                        if verbose: print('Kills: %s' % (kills))\n                        for kill in kills:\n                                # if verbose: print('lastquote=%s' % traders[kill].lastquote)\n                                if traders[kill].lastquote != None :\n                                        if verbose: print('Killing order %s' % (str(traders[kill].lastquote)))\n\n                                        can_order = traders[kill].lastquote\n                                        can_order.ostyle = \"CAN\"\n                                        exch_response = exchanges[0].process_order(time, can_order, process_verbose)\n                                        exch_msg = exch_response['trader_msgs']\n                                        # do the necessary book-keeping\n                                        # NB this assumes CAN results in a single message back from the exchange\n                                        traders[kill].bookkeep(exch_msg[0], time, bookkeep_verbose)\n\n                for t in traders:\n                        if len(traders[t].orders) > 0:\n                                # print(\"Tyme=%5.2d TID=%s Orders[0]=%s\" % (time, traders[t].tid, traders[t].orders[0]))\n                                dummy = 0 # NOP\n\n                # get public lob data from each exchange\n                lobs = []\n                for e in range(n_exchanges):\n                        exch = exchanges[e]\n                        lob = exch.publish_lob(time, tape_depth, lob_verbose)\n                        # if verbose: print ('Exchange %d, Published LOB=%s' % (e, str(lob)))\n\n                        lobs.append(lob)\n\n\n                # quantity-spike injection\n                # this next bit is a KLUDGE that is VERY FRAGILE and has lots of ARBITRARY CONSTANTS in it :-(\n                # it is introduced for George Church's project\n                # to edit this you have to know how many traders there are (specified in main loop)\n                # and you have to know the details of the supply and demand curves too (again, spec in main loop)\n                # before public release of this code, tidy it up and parameterise it nicely\n                # triggertime = 20\n                # replenish_period = 20\n                # highest_buyer_index = 10         # this buyer has the highest limit price\n                # highest_seller_index = 20\n                # big_qty = 222\n                #\n                # if time > (triggertime - 3*timestep)  and ((time+3*timestep) % replenish_period) <= (timestep):\n                #         # sys.exit('Bailing at injection trigger, time = %f' % time)\n                #         print ('time: %f')%(time)\n                #         # here we inject big quantities nto both buyer and seller sides... hopefully the injected traders will do a deal\n                #         pending_cust_orders[0].qty = big_qty\n                #\n                #\n                #         # pending_cust_orders[highest_seller_index-1].qty = big_qty\n                #\n                #         if verbose: print ('t:%f SPIKE INJECTION (Post) Exchange %d, Published LOB=%s' % (time, e, str(lob)))\n                #\n                #         print('t:%f, Spike Injection: , microp=%s, pending_cust_orders:' % (time, lob['microprice']) )\n                #         for order in pending_cust_orders: print('%s; ' % str(order))\n\n                triggertime = 100\n                replenish_period = 100\n                highest_buyer_index = 10         # this buyer has the highest limit price\n                highest_seller_index = 20\n                big_qty = 200\n                if time > (triggertime - 3*timestep) and ((time+3*timestep) % replenish_period) <= (2 * timestep):\n                        # sys.exit('Bailing at injection trigger, time = %f' % time)\n                        ##print \"inject at\", time\n                        for assigment in pending_cust_orders:\n                                if traders[assigment.trad_id].ttype == 'AAAA':\n                                        assigment.qty = big_qty\n                                        # print 'block order comes in'\n                                        # print 'trad_id: %s, price: %i qty: %i , time : %i' %(assigment.trad_id,assigment.price,assigment.qty,assigment.time)\n\n                # get a quote (or None) from a randomly chosen trader\n\n                # first randomly select a trader id\n                old_tid = tid\n                while tid == old_tid:\n                        tid = list(traders.keys())[random.randint(0, len(traders) - 1)]\n\n                # currently, all quotes/orders are issued only to the single exchange at exchanges[0]\n                # it is that exchange's responsibility to then deal with Order Protection / trade-through (Reg NMS Rule611)\n                # i.e. the exchange logic could/should be extended to check the best LOB price of each other exchange\n                # that is yet to be implemented here\n                # if((time >= replenish_period and time % replenish_period <= 0.001)):\n                #         print 'time: %f' %(time)\n                #         tid = 'B00'\n                #         order = traders[tid].getorder(time, time_left, lobs[0], verbose)\n                #         print str(order);\n                #         print '11111111111111111111111'\n                #\n                # else:\n                #         order = traders[tid].getorder(time, time_left, lobs[0], verbose)\n\n                # if((time >= replenish_period and time % replenish_period <= 0.05)):\n                #         print 'time: %f' %(time)\n                #         tid = 'B00'\n                #         order = traders[tid].getorder(time, time_left, lobs[0], verbose)\n                #         print str(order);\n                #         print '11111111111111111111111'\n                #\n                # else:\n                #         order = traders[tid].getorder(time, time_left, lobs[0], verbose)\n\n                order = traders[tid].getorder(time, time_left, lobs[0], verbose)\n\n\n\n                if order != None:\n                    # print ''\n                    # print ''\n                    # print ''\n                    # print('Trader Order: %s' % str(order))\n\n                    order.myref = traders[tid].orders[0].assignmentid  # attach customer order ID to this exchange order\n                    if verbose: print('Order with myref=%s' % order.myref)\n\n                    # Sanity check: catch bad traders here\n                    traderprice = traders[tid].orders[0].price\n                    if order.otype == 'Ask' and order.price < traderprice: sys.exit('Bad ask: Trader.price %s, Quote: %s' % (traderprice,order))\n                    if order.otype == 'Bid' and order.price > traderprice: sys.exit('Bad bid: Trader.price %s, Quote: %s' % (traderprice,order))\n\n\n                    # how many quotes does this trader already have sat on an exchange?\n\n                    if len(traders[tid].quotes) >= traders[tid].max_quotes :\n                            # need to clear a space on the trader's list of quotes, by deleting one\n                            # new quote replaces trader's oldest previous quote\n                            # bit of a  kludge -- just deletes oldest quote, which is at head of list\n                            # THIS SHOULD BE IN TRADER NOT IN MAIN LOOP?? TODO\n                            can_order = traders[tid].quotes[0]\n                            if verbose: print('> can_order %s' % str(can_order))\n                            can_order.ostyle = \"CAN\"\n                            if verbose: print('> can_order %s' % str(can_order))\n\n                            # send cancellation to exchange\n                            exch_response = exchanges[0].process_order(time, can_order, process_verbose)\n                            exch_msg = exch_response['trader_msgs']\n                            tape_sum = exch_response['tape_summary']\n\n                            if verbose:\n                                    print('>Exchanges[0]ProcessOrder: tradernquotes=%d, quotes=[' % len(traders[tid].quotes))\n                                    for q in traders[tid].quotes: print('%s' % str(q))\n                                    print(']')\n                                    for t in traders:\n                                            if len(traders[t].orders) > 0:\n                                                    # print(\">Exchanges[0]ProcessOrder: Tyme=%5.2d TID=%s Orders[0]=%s\" % (time, traders[t].tid, traders[t].orders[0]))\n                                                    NOP = 0\n                                            if len(traders[t].quotes) > 0:\n                                                    # print(\">Exchanges[0]ProcessOrder: Tyme=%5.2d TID=%s Quotes[0]=%s\" % (time, traders[t].tid, traders[t].quotes[0]))\n                                                    NOP = 0\n\n                            # do the necessary book-keeping\n                            # NB this assumes CAN results in a single message back from the exchange\n                            traders[tid].bookkeep(exch_msg[0], time, bookkeep_verbose)\n\n                    if verbose:\n                            # print('post-check: tradernquotes=%d, quotes=[' % len(traders[tid].quotes))\n                            for q in traders[tid].quotes: print('%s' % str(q))\n                            print(']')\n                            for t in traders:\n                                if len(traders[t].orders) > 0:\n                                        # print(\"PostCheck Tyme=%5.2d TID=%s Orders[0]=%s\" % (time, traders[t].tid, traders[t].orders[0]))\n                                        if len(traders[t].quotes) > 0:\n                                                # print(\"PostCheck Tyme=%5.2d TID=%s Quotes[0]=%s\" % (time, traders[t].tid, traders[t].quotes[0]))\n                                                NOP = 0\n\n                                if len(traders[t].orders) > 0 and traders[t].orders[0].astyle == \"CAN\":\n                                        sys.stdout.flush()\n                                        sys.exit(\"CAN error\")\n\n\n                    # add order to list of live orders issued by this trader\n                    traders[tid].quotes.append(order)\n\n                    if verbose: print('Trader %s quotes[-1]: %s' % (tid, traders[tid].quotes[-1]))\n\n                    # send this order to exchange and receive response\n                    exch_response = exchanges[0].process_order(time, order, process_verbose)\n                    exch_msgs = exch_response['trader_msgs']\n                    tape_sum = exch_response['tape_summary']\n\n                    # because the order just processed might have changed things, now go through each\n                    # order resting at the exchange and see if it can now be processed\n                    # applies to AON, ICE, OSO, and OCO\n\n\n\n\n\n                    #print('Exch_Msgs: ')\n                    # if exch_msgs == None: pass\n                    # else:\n                    #         for msg in exch_msgs:\n                    #             print('Msg=%s' % msg)\n\n                    if exch_msgs != None and len(exch_msgs) > 0:\n                                # messages to process\n                                for msg in exch_msgs:\n                                        if verbose: print('Message: %s' % msg)\n                                        traders[msg.tid].bookkeep(msg, time, bookkeep_verbose)\n\n\n                    # traders respond to whatever happened\n                    # needs to be updated for multiple exchanges\n                    lob = exchanges[0].publish_lob(time, tape_depth, lob_verbose)\n\n                    s = '%6.2f, ' % time\n                    for t in traders:\n                                # NB respond just updates trader's internal variables\n                                # doesn't alter the LOB, so processing each trader in\n                                # sequence (rather than random/shuffle) isn't a problem\n                                traders[t].respond(time, lob, tape_sum, respond_verbose)\n\n                                # if traders[t].ttype == 'ISHV':\n                                #         print('%6.2f, ISHV Print, %s' % (time, str(traders[t])))\n                                #         lq = traders[t].lastquote\n                                #         print('lq = %s' % lq)\n                                #         if lq != None :\n                                #                 price = lq.price\n                                #         else: price = None\n                                #         if price == None: s = s + '-1, '\n                                #         else: s = s + '%s, ' % price\n                    # prices_data_file.write('%s\\n' % s)\n\n                    # if (lob['microprice'] == None or lob['midprice'] == None):\n                    #         print 'microprice is none'\n                    #         print 'midprice is none '\n                    # print 'microprice: '\n                    # print lob['microprice']\n                    # print 'midprice: '\n                    # print lob['midprice']\n                    # print 'bid anon:'\n                    # print lob['bids']['lob']\n                    # print 'ask anon:'\n                    # print lob['asks']['lob']\n\n                time = time + timestep\n\n\n        # end of an experiment -- dump the tape\n        exchanges[0].dump_tape(sess_id, tapedumpfile, 'keep',traders)\n\n\n        # traders dump their blotters\n        for t in traders:\n                tid = traders[t].tid\n                ttype = traders[t].ttype\n                balance = traders[t].balance\n                blot = traders[t].blotter\n                blot_len = len(blot)\n                # build csv string for all events in blotter\n                csv = ''\n                estr = \"TODO \"\n                for e in blot:\n                        # print(blot)\n                        # estr = '%s, %s, %s, %s, %s, %s, ' % (e['type'], e['time'], e['price'], e['qty'], e['party1'], e['party2'])\n                        csv = csv + estr\n                blotterdumpfile.write('%s, %s, %s, %s, %s, %s\\n' % (sess_id, tid, ttype, balance, blot_len, csv))\n\n        # write summary trade_stats for this experiment (end-of-session summary ONLY)\n        for e in range(n_exchanges):\n                trade_stats(sess_id, traders, summaryfile, time, exchanges[e].publish_lob(time, None, lob_verbose))\n\n\n\n#############################\n\n# # Below here is where we set up and run a series of experiments\n\n\nif __name__ == \"__main__\":\n\n\n    start_time = 0.0\n    end_time = 200.0\n    duration = end_time - start_time\n\n    range1 = (50,50)\n    range2 = (20,20)\n    supply_schedule = [{'from': 0, 'to': end_time, 'ranges': [range1], 'stepmode': 'fixed'}]\n    # supply_schedule = [{'from': 0, 'to': 100, 'ranges': [(50,50)], 'stepmode': 'fixed'},\n    #                    {'from': 100, 'to': 200, 'ranges': [(50,150)], 'stepmode': 'fixed'},\n    #                    {'from': 200, 'to': 300, 'ranges': [(50,150)], 'stepmode': 'fixed'},\n    #                    {'from': 300, 'to': 500, 'ranges': [(50,50)], 'stepmode': 'fixed'}\n    #\n    #                    ]\n\n    range3 = (150, 150)\n    range4 = (100, 100)\n    demand_schedule = [{'from': 0, 'to': end_time, 'ranges': [range3], 'stepmode': 'fixed'}]\n    # demand_schedule = [{'from': 0, 'to': 100, 'ranges': [(150,150)], 'stepmode': 'fixed'},\n    #                    {'from': 100, 'to': 200, 'ranges': [(50,150)], 'stepmode': 'fixed'},\n    #                    {'from': 200, 'to': 300, 'ranges': [(150,150)], 'stepmode': 'fixed'},\n    #                    {'from': 300, 'to': 500, 'ranges': [(50,150)], 'stepmode': 'fixed'}\n    #\n    #                    ]\n\n    order_sched = {'sup': supply_schedule, 'dem': demand_schedule,\n                   'interval': 100,\n                   'timemode': 'periodic'}\n\n    ## 'AAAA' holds the block order\n    buyers_spec = [('AAA',10),('AAAA',10)]\n    sellers_spec = [ ('AA',10),('IAA_MLOFI',10)]\n    # buyers_spec = [('BID_IGDX_3', 10), ('BID_IZIP_3', 10), ('BID_IAA_3', 10),('BID_ISHV_3', 10),  ('AAAA', 10)]\n    # sellers_spec = [('BID_IGDX_3', 10), ('BID_IZIP_3', 10), ('BID_IAA_3', 10),('BID_ISHV_3', 10),  ('AAAA', 10)]\n    traders_spec = {'sellers':sellers_spec, 'buyers':buyers_spec}\n\n    sys.stdout.flush()\n\n    fname = 'Mybalances.csv'\n    summary_data_file = open(fname, 'w')\n\n    fname = 'Mytapes.csv'\n    tape_data_file = open(fname, 'w')\n\n    fname = 'Myblotters.csv'\n    blotter_data_file = open(fname, 'w')\n\n    for session in range(100):\n            sess_id = 'Test%02d' % session\n            print('Session %s; ' % sess_id)\n\n\n            market_session(sess_id, start_time, end_time, traders_spec, order_sched, summary_data_file, tape_data_file, blotter_data_file, True, False)\n\n    summary_data_file.close()\n    tape_data_file.close()\n    blotter_data_file.close()\n\n    print('\\n Experiment Finished')\n"
  },
  {
    "path": "ZhenZhang/source/BSE2_msg_classes.py",
    "content": "# Assignment:\n# The details of a customer's order/request, assigned to a trader\nclass Assignment:\n\n        def __init__(self, customer_id, trader_id, otype, ostyle, price, qty, time, endtime, assignmentid):\n                self.cust_id = customer_id      # customer identifier\n                self.trad_id = trader_id        # trader this customer order is assigned to\n                self.atype = otype              # order type (buy or sell)\n                self.astyle = ostyle            # order style: MKT, LIM, etc\n                self.price = price              # price\n                self.qty = qty                  # quantity\n                self.time = time                # timestamp: time at which customer issued order\n                self.endtime = endtime          # time at which order should expire (e.g. for GFD and AON orders)\n                self.assignmentid = assignmentid  # i.d. (unique identifier for each assignment)\n\n\n        def __str__(self):\n                return '[%s %s %s %s P=%03d Q=%s T=%5.2f AID:%d]' % \\\n                       (self.cust_id, self.trad_id, self.atype, self.astyle, self.price, self.qty, self.time, self.assignmentid)\n\n\n# Order/quote, submitted by trader to exchange\n# has a trader id, a type (buy/sell), a style (LIM, MKT, etc), a price,\n# a quantity, a timestamp, and a unique i.d.\n# The order-style may require additional parameters which are bundled into style_params (=None if not)\nclass Order:\n\n        def __init__(self, trader_id, otype, ostyle, price, qty, time, endtime, orderid):\n                self.tid = trader_id    # trader i.d.\n                self.otype = otype      # order type (bid or ask -- what side of LOB is it for)\n                self.ostyle = ostyle    # order style: MKT, LIM, etc\n                self.price = price      # price\n                self.qty = qty          # quantity\n                self.time = time        # timestamp\n                self.endtime = endtime  # time at which exchange deletes order (e.g. for GFD and AON orders)\n                self.orderid = orderid  # quote i.d. (unique to each quote, assigned by exchange)\n                self.myref = None       # trader's own reference for this order -- used to link back to assignment-ID\n                self.styleparams = None # style parameters -- initially null, filled in later\n\n        def __str__(self):\n                return '[%s %s %s P=%03d Q=%s T=%5.2f OID:%d Params=%s MyRef=%s]' % \\\n                       (self.tid, self.otype, self.ostyle, self.price, self.qty, self.time, self.orderid, str(self.styleparams), self.myref)\n\n\n# structure of the messages that the exchange sends back to the traders after processing an order\nclass Exch_msg:\n\n        def __init__(self, trader_id, order_id, eventtype, transactions, revised_order, fee, balance):\n                self.tid = trader_id            # trader i.d.\n                self.oid = order_id             # order i.d.\n                self.event = eventtype          # what happened? (ACKnowledged|PARTial|FILLed|FAILure)\n                self.trns = transactions        # list of transactions (price, qty, etc) details for this order\n                self.revo = revised_order       # revised order as created by exchange matching engine\n                self.fee = fee                  # exchange fee\n                self.balance = balance          # exchange's record of this trader's balance\n\n        def __str__(self):\n                return 'TID:%s OID:%s Event:%s Trns:%s RevO:%s Fee:%d Bal:%d' % \\\n                       (self.tid, self.oid, self.event, str(self.trns), str(self.revo), self.fee, self.balance)\n"
  },
  {
    "path": "ZhenZhang/source/BSE_trader_agents.py",
    "content": "\nfrom BSE2_msg_classes import Assignment, Order, Exch_msg\n\n\n##################--Traders below here--#############\nimport random\nimport math\n##################--Traders below here--#############\n\nbse_sys_minprice = 1  # minimum price in the system, in cents/pennies\nbse_sys_maxprice = 200  # maximum price in the system, in cents/pennies\n\n# Trader superclass\n# all Traders have a trader id, bank balance, blotter, and list of orders to execute\nclass Trader:\n\n        def __init__(self, ttype, tid, balance, time):\n                self.ttype = ttype      # what type / strategy this trader is\n                self.tid = tid          # trader unique ID code\n                self.balance = balance  # money in the bank\n                self.blotter = []       # record of trades executed\n                self.orders = []        # customer orders currently being worked\n                self.max_cust_orders = 1        # maximum number of distinct customer orders allowed at any one time.\n                self.quotes = []        # distinct quotes currently live on the LOB\n                self.max_quotes = 1     # maximum number of distinct quotes allowed on LOB\n                self.willing = 1        # used in ZIP etc\n                self.able = 1           # used in ZIP etc\n                self.birthtime = time   # used when calculating age of a trader/strategy\n                self.profitpertime = 0  # profit per unit time\n                self.n_trades = 0       # how many trades has this trader done?\n                self.lastquote = None   # record of what its most recent quote was/is (incl price)\n\n\n        def __str__(self):\n                blotterstring = ''\n                for b in self.blotter :\n                        blotterstring = blotterstring + '[[%s], %s]' % (str(b[0]), b[1])\n                return '[TID=%s type=%s balance=%s blotter=%s orders=%s n_trades=%s profitpertime=%s]' \\\n                       % (self.tid, self.ttype, self.balance, blotterstring, self.orders, self.n_trades, self.profitpertime)\n\n\n        def add_cust_order(self, order, verbose):\n                # add a customer order to trader's records\n                # currently LAZY: keeps to within max_cust_orders by appending new order and deleting head self.orders\n                if len(self.quotes) > 0:\n                    # this trader has a live quote on the LOB, from a previous customer order\n                    # need response to signal cancellation/withdrawal of that quote\n                    response = 'LOB_Cancel'\n                else:\n                    response = 'Proceed'\n                if len(self.orders) >= self.max_cust_orders:\n                        self.orders = self.orders[1:]\n                self.orders.append(order)\n                if verbose: print('add_order < response=%s self.orders=%s' % (response, str(self.orders)))\n                return response\n\n\n        # delete a customer order from trader's list of orders being worked\n        def del_cust_order(self, cust_order_id, verbose):\n                if verbose:\n                        print('>del_cust_order: Cust_orderID=%s; self.orders=' % cust_order_id)\n                        for o in self.orders: print('%s ' % str(o))\n\n                cust_orders = []\n                for co in self.orders:\n                        if co.assignmentid != cust_order_id: cust_orders.append(co)\n\n                self.orders = cust_orders\n\n\n        # revise a customer order: used after a PARTial fill on the exchange\n        def revise_cust_order(self, cust_order_id, revised_order, verbose):\n                if verbose:\n                        print('>revise_cust_order: Cust_orderID=%s; revised_order=%s, self.orders=' % (cust_order_id, revised_order))\n                        for o in self.orders: print('%s ' % str(o))\n\n                cust_orders = []\n                for co in self.orders:\n                        if co.assignmentid != cust_order_id: cust_orders.append(co)\n                        else:\n                                revised_assignment = co\n                                revised_assignment.qty = revised_order.qty\n                                cust_orders.append(revised_assignment)\n\n                self.orders = cust_orders\n\n                if verbose:\n                        print('<revise_cust_order: Cust_orderID=%s; revised_order=%s, self.orders=' % (cust_order_id, revised_order))\n                        for o in self.orders: print('%s ' % str(o))\n\n\n        # delete an order/quote from the trader's list of its orders live on the exchange\n        def del_exch_order(self, oid, verbose):\n                if verbose:\n                        print('>del_exch_order: OID:%d; self.quotes=' % oid)\n                        for q in self.quotes: print('%s ' % str(q))\n\n                exch_orders = []\n                for eo in self.quotes:\n                        if eo.orderid != oid: exch_orders.append(eo)\n\n                self.quotes= exch_orders\n\n\n        def bookkeep(self, msg, time, verbose):\n                # bookkeep(): trader book-keeping in response to message from the exchange\n                # update records of what orders are still being worked, account balance, etc.\n                # trader's blotter is a simple sequential record of each exchange messages received, and the trader's balance after bookeeping that msh\n\n                if verbose: print('>bookkeep msg=%s bal=%d' % (msg, self.balance))\n\n                profit = 0\n\n                if msg.event == \"CAN\":\n                        # order was cancelled at the exchange\n                        # so delete the order from the trader's records of what quotes it has live on the exchange\n                        if verbose:\n                                print(\">CANcellation: msg=%s quotes=\" % str(msg))\n                                for q in self.quotes: print(\"%s\" % str(q))\n\n                        newquotes = []\n                        for q in self.quotes:\n                                if q.orderid != msg.oid:\n                                        newquotes.append(q)\n                        self.quotes = newquotes\n\n                        if verbose:\n                                print(\"<CANcellation: quotes=\")\n                                for q in self.quotes: print(\"%s\" % str(q))\n\n\n                # an individual order of some types (e.g. MKT) can fill via transactions at different prices\n                # so the message that comes back from the exchange has transaction data in a list: will often be length=1\n\n                if msg.event == \"FILL\" or msg.event == \"PART\":\n\n                        for trans in msg.trns:\n                                transactionprice = trans[\"Price\"]\n                                qty = trans[\"Qty\"]\n\n                                # find this LOB order in the trader's list of quotes sent to exchange\n                                exch_order = None\n                                for ord in self.quotes:\n                                        if ord.orderid == msg.oid:\n                                                exch_order = ord\n                                        break\n                                if exch_order == None:\n                                        s = 'FAIL: bookkeep() cant find order (msg.oid=%d) orders=' % msg.oid\n                                        for ord in self.quotes: s = s + str(ord)\n                                        sys.exit(s)\n\n                                cust_order_id = exch_order.myref\n                                cust_order = None\n                                for assignment in self.orders:\n                                        if assignment.assignmentid == cust_order_id:\n                                                cust_order = assignment\n                                                break\n\n                                limitprice = cust_order.price\n\n                                if exch_order.otype == 'Bid':\n                                        profit = (limitprice - transactionprice) * qty\n                                else:\n                                        profit = (transactionprice - limitprice) * qty\n\n                                self.balance += profit\n                                self.n_trades += 1\n                                age = time - self.birthtime\n                                self.profitpertime = self.balance / age\n\n\n\n\n\n\n                                if verbose: print('Price=%d Limit=%d Q=%d Profit=%d N_trades=%d Age=%f Balance=%d' %\n                                                  (transactionprice, limitprice, qty, profit, self.n_trades, age, self.balance))\n\n                                if profit < 0 :\n                                        print self.tid\n                                        print self.ttype\n                                        print profit\n                                        print exch_order\n                                        sys.exit('Exit: Negative profit')\n\n                        if verbose: print('%s: profit=%d bal=%d profit/time=%f' %\n                                  (self.tid, profit, self.balance, self.profitpertime))\n\n                        # by the time we get to here, exch_order is instantiated\n                        cust_order_id = exch_order.myref\n\n                        if msg.event == \"FILL\":\n                                # this order has completed in full, so it thereby completes the corresponding customer order\n                                # so delete both the customer order from trader's record of those\n                                # and the order has already been deleted from the exchange's records, so also needs to be deleted from trader's records of orders held at exchange\n                                cust_order_id = exch_order.myref\n                                if verbose: print('>bookkeep() deleting customer order ID=%s' % cust_order_id)\n                                self.del_cust_order(cust_order_id, verbose)  # delete this customer order\n                                if verbose: print(\">bookkeep() deleting OID:%d from trader's exchange-order records\" % exch_order.orderid)\n                                self.del_exch_order(exch_order.orderid, verbose) # delete the exchange-order from trader's records\n\n                        elif msg.event == \"PART\":\n                                # the customer order is still live, but its quantity needs updating\n                                if verbose: print('>bookkeep() PART-filled order updating qty on customer order ID=%s' % cust_order_id)\n                                self.revise_cust_order(cust_order_id, msg.revo, verbose)  # delete this customer order\n\n                                if exch_order.ostyle == \"IOC\":\n                                        # a partially filled IOC has the non-filled portion cancelled at the exchange,\n                                        # so the trader's order records need to be updated accordingly\n                                        if verbose: print(\">bookkeep() PART-filled IOC cancels remainder: deleting OID:%d from trader's exchange-order records\" % exch_order.orderid)\n                                        self.del_exch_order(exch_order.orderid, verbose)  # delete the exchange-order from trader's records\n\n                self.blotter.append([msg, self.balance])  # add trade record to trader's blotter\n\n\n\n        # specify how trader responds to events in the market\n        # this is a null action, expect it to be overloaded by specific algos\n        def respond(self, time, lob, trade, verbose):\n                return None\n\n\n        # specify how trader mutates its parameter values\n        # this is a null action, expect it to be overloaded by specific algos\n        def mutate(self, time, lob, trade, verbose):\n                return None\n\n\n# Trader subclass Giveaway\n# even dumber than a ZI-U: just give the deal away\n# (but never makes a loss)\nclass Trader_Giveaway(Trader):\n\n        def getorder(self, time, countdown, lob, verbose):\n\n                if verbose: print('GVWY getorder:')\n\n                if len(self.orders) < 1:\n                        order = None\n                else:\n                        quoteprice = self.orders[0].price\n                        order = Order(self.tid,\n                                    self.orders[0].atype,\n                                    self.orders[0].astyle,\n                                    quoteprice,\n                                    self.orders[0].qty,\n                                    time, None, -1)\n                        self.lastquote=order\n                return order\n\n\n\n# Trader subclass ZI-C\n# After Gode & Sunder 1993\nclass Trader_ZIC(Trader):\n\n        def getorder(self, time, countdown, lob, verbose):\n\n                if verbose: print('ZIC getorder:')\n\n                if len(self.orders) < 1:\n                        # no orders: return NULL\n                        order = None\n                else:\n                        minprice = lob['bids']['worstp']\n                        maxprice = lob['asks']['worstp']\n\n                        limit = self.orders[0].price\n                        otype = self.orders[0].atype\n                        ostyle = self.orders[0].astyle\n                        if otype == 'Bid':\n                                oprice = random.randint(minprice, limit)\n                        else:\n                                oprice = random.randint(limit, maxprice)\n                                # NB should check it == 'Ask' and barf if not\n                        order = Order(self.tid, otype, ostyle, oprice, self.orders[0].qty, time, None, -1)\n                        self.lastquote = order\n                return order\n\n\n\n# Trader subclass Shaver\n# shaves a penny off the best price\nclass Trader_Shaver(Trader):\n\n        def getorder(self, time, countdown, lob, verbose):\n\n                if verbose: print(\"SHVR getorder:\")\n\n                if len(self.orders) < 1:\n                        order = None\n                else:\n                        if verbose: print(\" self.orders[0]=%s\" % str(self.orders[0]))\n                        limitprice = self.orders[0].price\n                        otype = self.orders[0].atype\n                        ostyle = self.orders[0].astyle\n                        if otype == 'Bid':\n                                if lob['bids']['n'] > 0:\n                                        quoteprice = lob['bids']['bestp'] + 1\n                                        if quoteprice > limitprice :\n                                                quoteprice = limitprice\n                                else:\n                                        quoteprice = lob['bids']['worstp']\n                        else:\n                                if lob['asks']['n'] > 0:\n                                        quoteprice = lob['asks']['bestp'] - 1\n                                        if quoteprice < limitprice:\n                                                quoteprice = limitprice\n                                else:\n                                        quoteprice = lob['asks']['worstp']\n                        order = Order(self.tid, otype, ostyle, quoteprice, self.orders[0].qty, time, None, -1)\n                        self.lastquote = order\n                return order\n\n\n\n# Trader subclass Imbalance-sensitive Shaver\n# shaves X off the best price, where X depends on supply/demand imbalance\nclass Trader_ISHV(Trader):\n\n\n        def getorder(self, time, countdown, lob, verbose):\n\n                if verbose: print(\"ISHV getorder:\")\n\n                shave_c = 2 # c in the y=mx+c linear mapping from imbalance to shave amount\n                shave_m = 1 # m in the y=mx+c\n\n                if len(self.orders) < 1:\n                        order = None\n                else:\n                        if verbose: print(\" self.orders[0]=%s\" % str(self.orders[0]))\n                        limitprice = self.orders[0].price\n                        otype = self.orders[0].atype\n                        ostyle = self.orders[0].astyle\n\n                        microp = lob['microprice']\n                        midp = lob['midprice']\n\n                        if microp != None and midp != None:\n                                imbalance = microp - midp\n                        else: imbalance = 0 # if imbalance is undefined, proceed as if it is equal to zero\n\n\n                        if otype == 'Bid':\n\n                                # quantity sensitivity\n                                if imbalance < 0 : shaving = 1 # imbalance in favour of buyers, so shave slowly\n                                else: shaving = shave_c + (shave_m * int(imbalance*100)/100) # shave ever larger amounts\n\n                                # print('t:%f, ISHV (Bid) imbalance=%s shaving=%s' % (time, imbalance, shaving))\n\n                                if len(lob['bids']['lob']) > 0:\n                                        quoteprice = lob['bids']['bestp'] + shaving\n                                        if quoteprice > limitprice :\n                                                quoteprice = limitprice\n                                else:\n                                        quoteprice = 1 #KLUDGE -- come back to fix todo\n                        else:\n                                # quantity sensitivity\n                                if imbalance > 0 : shaving = 1\n                                else: shaving = shave_c - (shave_m * int(imbalance*100)/100)\n\n                                # print('t:%f, ISHV (Ask) imbalance=%s shaving=%s' % (time, imbalance, shaving))\n\n                                if len(lob['asks']['lob']) > 0:\n                                        quoteprice = lob['asks']['bestp'] - shaving\n                                        if quoteprice < limitprice :\n                                                quoteprice = limitprice\n                                else:\n                                        quoteprice = 200 #KLUDGE -- come back to fix todo\n\n                        order = Order(self.tid, otype, ostyle, quoteprice, self.orders[0].qty, time, None, verbose)\n                        self.lastquote = order\n                return order\n\n\n\n# Trader subclass Sniper\n# Based on Shaver, inspired by Kaplan\n# \"lurks\" until time remaining < threshold% of the trading session\n# then gets increasing aggressive, increasing \"shave thickness\" as time runs out\nclass Trader_Sniper(Trader):\n\n        def getorder(self, time, countdown, lob, verbose):\n\n                if verbose: print('SNPR getorder: self.orders[0]=%s' % str(self.orders[0]))\n\n                lurk_threshold = 0.2\n                shavegrowthrate = 3\n                shave = int(1.0 / (0.01 + countdown / (shavegrowthrate * lurk_threshold)))\n                if (len(self.orders) < 1) or (countdown > lurk_threshold):\n                        order = None\n                else:\n                        limitprice = self.orders[0].price\n                        otype = self.orders[0].otype\n                        ostyle = self.orders[0].ostyle\n                        if otype == 'Bid':\n                                if lob['bids']['n'] > 0:\n                                        oprice = lob['bids']['bestp'] + shave\n                                        if oprice > limitprice:\n                                                oprice = limitprice\n                                else:\n                                        oprice = lob['bids']['worstp']\n                        else:\n                                if lob['asks']['n'] > 0:\n                                        oprice = lob['asks']['bestp'] - shave\n                                        if oprice < limitprice:\n                                                oprice = limitprice\n                                else:\n                                        oprice = lob['asks']['worstp']\n                        order = Order(self.tid, otype, ostyle, oprice, self.orders[0].qty, time, None, -1)\n                        self.lastquote = order\n                return order\n\n\n\n# Trader subclass ZIP\n# After Cliff 1997\nclass Trader_ZIP(Trader):\n\n        # ZIP init key param-values are those used in Cliff's 1997 original HP Labs tech report\n        # NB this implementation keeps separate margin values for buying & selling,\n        #    so a single trader can both buy AND sell\n        #    -- in the original, traders were either buyers OR sellers\n\n        def __init__(self, ttype, tid, balance, time):\n                Trader.__init__(self, ttype, tid, balance, time)\n                m_fix = 0.05\n                m_var = 0.05\n                self.job = None                                 # this is 'Bid' or 'Ask' depending on customer order\n                self.active = False                             # gets switched to True while actively working an order\n                self.prev_change = 0                            # this was called last_d in Cliff'97\n                self.beta = 0.1 + 0.2 * random.random()         # learning rate\n                self.momntm = 0.3 * random.random()             # momentum\n                self.ca = 0.10                                  # self.ca & .cr were hard-coded in '97 but parameterised later\n                self.cr = 0.10\n                self.margin = None                              # this was called profit in Cliff'97\n                self.margin_buy = -1.0 * (m_fix + m_var * random.random())\n                self.margin_sell = m_fix + m_var * random.random()\n                self.price = None\n                self.limit = None\n                # memory of best price & quantity of best bid and ask, on LOB on previous update\n                self.prev_best_bid_p = None\n                self.prev_best_bid_q = None\n                self.prev_best_ask_p = None\n                self.prev_best_ask_q = None\n                # memory of worst prices from customer orders received so far\n                self.worst_bidprice = None\n                self.worst_askprice = None\n\n\n        def __str__(self):\n                s = '%s, job=, %s, ' % (self.tid, self.job)\n                if self.active == True: s = s +'actv=,T, '\n                else: s = s + 'actv=,F, '\n                if self.margin == None: s = s + 'mrgn=,N,   '\n                else: s = s + 'mrgn=,%5.2f, ' % self.margin\n                s = s + 'lmt=,%s, price=,%s, bestbid=,%s,@,%s, bestask=,%s,@,%s, wrstbid=,%s, wrstask=,%s' %\\\n                    (self.limit, self.price, self.prev_best_bid_q, self.prev_best_bid_p, self.prev_best_ask_q, self.prev_best_ask_p, self.worst_bidprice, self.worst_askprice)\n                return(s)\n\n\n        def getorder(self, time, countdown, lob, verbose):\n\n                if verbose: print('ZIP getorder(): LOB=%s' % lob)\n\n                # random coefficient, multiplier on trader's own estimate of worst possible bid/ask prices\n                # currently in arbitrarily chosen range [2, 5]\n                worst_coeff = 2 + (3 * random.random())\n\n                if len(self.orders) < 1:\n                        self.active = False\n                        order = None\n                else:\n                        self.active = True\n                        self.limit = self.orders[0].price\n                        self.job = self.orders[0].atype\n                        if self.job == 'Bid':\n                                # currently a buyer (working a bid order)\n                                self.margin = self.margin_buy\n                                # what is the worst bid price on the LOB right now?\n                                if len(lob['bids']['lob']) > 0 :\n                                        # take price of final entry on LOB\n                                        worst_bid = lob['bids']['lob'][-1][0]\n                                else:\n                                        # local pessimistic estimate of the worst bid price (own version of stub quote)\n                                        worst_bid = max(1, int(self.limit / worst_coeff))\n                                if self.worst_bidprice == None: self.worst_bidprice = worst_bid\n                                elif self.worst_bidprice > worst_bid: self.worst_bidprice = worst_bid\n                        else:\n                                # currently a seller (working a sell order)\n                                self.margin = self.margin_sell\n                                # what is the worst ask price on the LOB right now?\n                                if len(lob['asks']['lob']) > 0 :\n                                        # take price of final entry on LOB\n                                        worst_ask = lob['asks']['lob'][-1][0]\n                                else:\n                                        # local pessimistic estimate of the worst ask price (own version of stub quote)\n                                        worst_ask = int(self.limit * worst_coeff)\n                                if self.worst_askprice == None: self.worst_askprice = worst_ask\n                                elif self.worst_askprice < worst_ask: self.worst_askprice = worst_ask\n\n                        quoteprice = int(self.limit * (1 + self.margin))\n                        self.price = quoteprice\n\n                        order = Order(self.tid, self.job, \"LIM\", quoteprice, self.orders[0].qty, time, None, -1)\n                        self.lastquote = order\n\n                return order\n\n\n        # update margin on basis of what happened in market\n        def respond(self, time, lob, trade, verbose):\n                # ZIP trader responds to market events, altering its margin\n                # does this whether it currently has an order to work or not\n\n                def target_up(price):\n                        # generate a higher target price by randomly perturbing given price\n                        ptrb_abs = self.ca * random.random()  # absolute shift\n                        ptrb_rel = price * (1.0 + (self.cr * random.random()))  # relative shift\n                        target = int(round(ptrb_rel + ptrb_abs, 0))\n                        if target == price: target = price + 1  # enforce minimal difference\n                        # print('TargetUp: %d %d\\n' % (price, target))\n                        return(target)\n\n\n                def target_down(price):\n                        # generate a lower target price by randomly perturbing given price\n                        ptrb_abs = self.ca * random.random()  # absolute shift\n                        ptrb_rel = price * (1.0 - (self.cr * random.random()))  # relative shift\n                        target = int(round(ptrb_rel - ptrb_abs, 0))\n                        if target == price : target = price -1 # enforce minimal difference\n                        # print('TargetDn: %d %d\\n' % (price,target))\n                        return(target)\n\n\n                def microshade(microprice, price):\n                        # shade in the direction of the microprice\n                        microweight = 0\n                        if microprice != None: shaded = ((microweight * microprice) + ((1 - microweight) * price))\n                        else: shaded = price\n                        # print('Microshade: micro=%s price=%s shaded=%s' % (microprice, price, shaded))\n                        return(shaded)\n\n\n                def willing_to_trade(price):\n                        # am I willing to trade at this price?\n                        willing = False\n                        if self.job == 'Bid' and self.active and self.price >= price:\n                                willing = True\n                        if self.job == 'Ask' and self.active and self.price <= price:\n                                willing = True\n                        return willing\n\n\n                def profit_alter(*argv):\n                        # this has variable number of parameters\n                        # if passed a single numeric value, that's the target price\n                        # if passed three numeric values, that's the price, beta (learning rate), and momentum\n                        if len(argv) == 1 :\n                                price = argv[0]\n                                beta = self.beta\n                                momntm = self.momntm\n                        elif len(argv) == 3 :\n                                price = argv[0]\n                                beta = argv[1]\n                                momntm = argv[2]\n                        else:\n                                sys.stdout.flush()\n                                sys.exit('Fail: ZIP profit_alter given wrong number of parameters')\n\n                        # print('profit_alter: price=%s beta=%s momntm=%s' % (price, beta, momntm))\n                        oldprice = self.price\n                        diff = price - oldprice\n                        change = ((1.0 - self.momntm) * (self.beta * diff)) + (self.momntm * self.prev_change)\n                        self.prev_change = change\n                        newmargin = ((self.price + change) / self.limit) - 1.0\n\n                        if self.job == 'Bid':\n                                margin = min(newmargin, 0)\n                                self.margin_buy = margin\n                                self.margin = margin\n                        else :\n                                margin = max(0, newmargin)\n                                self.margin_sell = margin\n                                self.margin = margin\n\n                        # set the price from limit and profit-margin\n                        self.price = int(round(self.limit * (1.0 + self.margin), 0))\n                        # print('old=%d diff=%d change=%d lim=%d price = %d\\n' % (oldprice, diff, change, self.limit, self.price))\n\n\n                if verbose and trade != None: print('respond() [ZIP] time=%s tid=%s, trade=%s LOB[bids]=%s LOB[asks]=%s' %\n                                                    (time, self.tid, trade, lob[\"bids\"], lob[\"asks\"]))\n\n\n                # what, if anything, has happened on the bid LOB?\n\n                # if trade != None: print('ZIP respond() trade=%s' % trade)\n\n                bid_improved = False\n                bid_hit = False\n\n                if len(lob['bids']['lob']) > 0: lob_best_bid_p = lob['bids']['lob'][0][0]\n                else: lob_best_bid_p = None\n\n                lob_best_bid_q = None                   # default assumption\n\n                if lob_best_bid_p != None:\n                        # non-empty bid LOB\n\n                        if self.prev_best_bid_p > lob_best_bid_p : best_bid_p_decreased = True\n                        else: best_bid_p_decreased = False\n\n                        if (self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q): same_p_smaller_q = True\n                        else: same_p_smaller_q = False\n\n                        lob_best_bid_q = lob['bids']['lob'][0][1]\n\n                        if self.prev_best_bid_p < lob_best_bid_p :\n                                # best bid has improved\n                                # NB doesn't check if the improvement was by self\n                                bid_improved = True\n                        elif trade != None and (best_bid_p_decreased or same_p_smaller_q) :\n                                # there WAS a trade and either...\n                                # ... (best bid price has gone DOWN) or (best bid price is same but quantity at that price has gone DOWN)\n                                # then assume previous best bid was hit\n                                bid_hit = True\n\n                elif self.prev_best_bid_p != None:\n                        # the bid LOB is empty now but was not previously: so was it canceled or lifted?\n                        if trade !=  None:\n                                # a trade has occurred and the previously nonempty ask LOB is now empty\n                                # so assume best ask was lifted\n                                bid_hit = True\n                        else:\n                                bid_hit = False\n\n                # if verbose: print(\"LOB[bids]=%s bid_improved=%s bid_hit=%s\" % (lob['bids'], bid_improved, bid_hit))\n\n\n                # what, if anything, has happened on the ask LOB?\n\n                ask_improved = False\n                ask_lifted = False\n\n                if len(lob['asks']['lob']) > 0: lob_best_ask_p = lob['asks']['lob'][0][0]\n                else: lob_best_ask_p = None\n\n                lob_best_ask_q = None\n\n                if lob_best_ask_p != None:\n                        # non-empty ask LOB\n\n                        if self.prev_best_ask_p < lob_best_ask_p: best_ask_p_increased = True\n                        else: best_ask_p_increased = False\n\n                        if (self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q): same_p_smaller_q = True\n                        else: same_p_smaller_q = False\n\n                        lob_best_ask_q = lob['asks']['lob'][0][1]\n                        if self.prev_best_ask_p > lob_best_ask_p :\n                                # best ask has improved -- NB doesn't check if the improvement was by self\n                                ask_improved = True\n                        elif trade != None and (best_ask_p_increased or same_p_smaller_q):\n                                # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\n                                ask_lifted = True\n\n                elif self.prev_best_ask_p != None:\n                        # the ask LOB is empty now but was not previously: so was it canceled or lifted?\n                        if trade !=  None:\n                                # a trade has occurred and the previously nonempty ask LOB is now empty\n                                # so assume best ask was lifted\n                                ask_lifted = True\n                        else:\n                                ask_lifted = False\n\n\n                # if verbose: print(\"LOB[asks]=%s ask_improved=%s ask_lifted=%s\" % (lob['asks'], ask_improved, ask_lifted))\n\n\n                if verbose and (bid_improved or bid_hit or ask_improved or ask_lifted):\n                        print('ZIP respond() B_improved=%s; B_hit=%s A_improved=%s, A_lifted=%s' % (bid_improved, bid_hit, ask_improved, ask_lifted))\n                        print('Trade=%s\\n' % trade)\n\n\n                # we want to know: did a deal just happen?\n                # if not, did the most recent bid\n\n\n                deal = bid_hit or ask_lifted\n\n\n                # previously...\n                # when raising margin, tradeprice = trade['price'], targetprice = f(tradeprice) &\n                # i.e. target price will be calculated relative to price of most recent transaction\n                # and when lowering margin, targetprice = f(best_price_on_counterparty_side_of_LOB) or\n                # or if LOB empty then targetprice = f(worst possible counterparty quote) <-- a system constant\n\n\n                # new in this version:\n                # take account of LOB's microprice if it is defined (if not, use trade['price'] as before)\n\n                midp = lob['midprice']\n                microp = lob['microprice']\n\n                # KLUDGE for TESTING\n                if time > 79: microp = 145\n\n                if microp != None and midp != None :\n                        imbalance = microp - midp\n                else:\n                        imbalance = 0  # uses zero instead of None because a zero imbalance reverts ZIP to original form\n\n\n                target_price = None # default assumption\n\n                # print('self.job=%s' % self.job)\n\n                if self.job == 'Ask':\n                        # seller\n                        if deal:\n                                if verbose: print ('trade',trade)\n                                tradeprice = trade['price']  # price of most recent transaction\n                                # print('tradeprice=%s lob[microprice]=%s' % (tradeprice, lob['microprice']))\n                                shadetrade = microshade(lob['microprice'], tradeprice)\n                                refprice = shadetrade\n\n                                if self.price <= tradeprice:\n                                        # could sell for more? raise margin\n                                        target_price = target_up(refprice)\n                                        profit_alter(target_price)\n                                elif ask_lifted and self.active and not willing_to_trade(tradeprice):\n                                        # previous best ask was hit,\n                                        # but this trader wouldn't have got the deal cos price to high,\n                                        # and still working a customer order, so reduce margin\n                                        target_price = target_down(refprice)\n                                        profit_alter(target_price)\n                        else:\n                                # no deal: aim for a target price higher than best bid\n                                # print('lob_best_bid_p=%s lob[microprice]=%s' % (lob_best_bid_p, lob['microprice']))\n                                refprice = microshade(lob['microprice'], lob_best_bid_p)\n\n                                if ask_improved and self.price > lob_best_bid_p:\n                                        if lob_best_bid_p != None:\n                                                target_price = target_up(lob_best_bid_p)\n                                        else:\n                                                if self.worst_askprice != None:\n                                                        target_price = self.worst_askprice\n                                                        # print('worst_askprice = %s' % self.worst_askprice)\n                                                        target_price = None #todo: does this stop the price-spikes?\n                                                else:   target_price = None\n                                                        # target_price = lob['asks']['worstp']  # stub quote\n                                        if target_price != None:\n                                                # print('PA1: tp=%s' % target_price)\n                                                profit_alter(target_price)\n\n                if self.job == 'Bid':\n                        # buyer\n                        if deal:\n                                tradeprice = trade['price']\n                                shadetrade = microshade(lob['microprice'], tradeprice)\n                                refprice = shadetrade\n\n                                if lob['microprice'] != None and lob['midprice'] != None:\n                                        delta = lob['microprice'] - lob['midprice']\n                                        # refprice = refprice + delta\n\n                                if self.price >= tradeprice :\n                                        # could buy for less? raise margin (i.e. cut the price)\n                                        target_price = target_down(refprice)\n                                        profit_alter(target_price)\n                                elif bid_hit and self.active and not willing_to_trade(tradeprice):\n                                        # wouldn't have got this deal, and still working a customer order,\n                                        # so reduce margin\n                                        target_price = target_up(refprice)\n                                        profit_alter(target_price)\n                        else:\n                                # no deal: aim for target price lower than best ask\n                                refprice = microshade(lob['microprice'], lob_best_ask_p)\n                                if bid_improved and self.price < lob_best_ask_p:\n                                        if lob_best_ask_p != None:\n                                                target_price = target_down(lob_best_ask_p)\n                                        else:\n                                                if self.worst_bidprice != None :\n                                                        target_price = self.worst_bidprice\n                                                        target_price = None\n                                                else:   target_price = None\n                                                        # target_price = lob['bids']['worstp']  # stub quote\n                                        if target_price != None:\n                                                # print('PA2: tp=%s' % target_price)\n                                                profit_alter(target_price)\n\n                # print('time,%f,>>>,microprice,%s,>>>,target_price,%s' % (time, lob['microprice'], target_price))\n\n                # remember the best LOB data ready for next response\n                self.prev_best_bid_p = lob_best_bid_p\n                self.prev_best_bid_q = lob_best_bid_q\n                self.prev_best_ask_p = lob_best_ask_p\n                self.prev_best_ask_q = lob_best_ask_q\n\n\n\n##########################---trader-types have all been defined now--################\n\n\nclass Trader_AA(Trader):\n\n        def __init__(self, ttype, tid, balance, time):\n                # Stuff about trader\n                # self.ttype = ttype\n                # self.tid = tid\n                # self.balance = balance\n                # self.birthtime = time\n                # self.profitpertime = 0\n                # self.n_trades = 0\n                # self.blotter = []\n                # self.orders = []\n                # self.n_quotes = 0\n                # self.lastquote = None\n                Trader.__init__(self, ttype, tid, balance, time)\n\n                self.limit = None\n                self.job = None\n\n                # learning variables\n                self.r_shout_change_relative = 0.05\n                self.r_shout_change_absolute = 0.05\n                self.short_term_learning_rate = random.uniform(0.1, 0.5)\n                self.long_term_learning_rate = random.uniform(0.1, 0.5)\n                self.moving_average_weight_decay = 0.95 # how fast weight decays with time, lower is quicker, 0.9 in vytelingum\n                self.moving_average_window_size = 5\n                self.offer_change_rate = 3.0\n                self.theta = -2.0\n                self.theta_max = 2.0\n                self.theta_min = -8.0\n                self.marketMax = bse_sys_maxprice\n\n                # Variables to describe the market\n                self.previous_transactions = []\n                self.moving_average_weights = []\n                for i in range(self.moving_average_window_size):\n                        self.moving_average_weights.append(self.moving_average_weight_decay**i)\n                self.estimated_equilibrium = []\n                self.smiths_alpha = []\n                self.prev_best_bid_p = None\n                self.prev_best_bid_q = None\n                self.prev_best_ask_p = None\n                self.prev_best_ask_q = None\n\n                # Trading Variables\n                self.r_shout = None\n                self.buy_target = None\n                self.sell_target = None\n                self.buy_r = -1.0 * (0.3 * random.random())\n                self.sell_r = -1.0 * (0.3 * random.random())\n\n\n\n        def calcEq(self): ##clear and correct\n                # Slightly modified from paper, it is unclear inpaper\n                # N previous transactions * weights / N in vytelingum, swap N denominator for sum of weights to be correct?\n                if len(self.previous_transactions) == 0:\n                        return\n                elif len(self.previous_transactions) < self.moving_average_window_size:\n                        # Not enough transactions\n                        self.estimated_equilibrium.append(float(sum(self.previous_transactions)) / max(len(self.previous_transactions), 1))\n                else:\n                        N_previous_transactions = self.previous_transactions[-self.moving_average_window_size:]\n                        thing = [N_previous_transactions[i]*self.moving_average_weights[i] for i in range(self.moving_average_window_size)]\n                        eq = sum( thing ) / sum(self.moving_average_weights)\n                        self.estimated_equilibrium.append(eq)\n\n        def calcAlpha(self): ##correct. but calcAlpha in snashall's version is incorrect\n                alpha = 0.0\n                for p in self.previous_transactions:\n                        alpha += (p - self.estimated_equilibrium[-1])**2\n                alpha = math.sqrt(alpha/len(self.previous_transactions))\n                self.smiths_alpha.append( alpha/self.estimated_equilibrium[-1] )\n\n        def calcTheta(self): ## clear and correct\n                gamma = 2.0 #not sensitive apparently so choose to be whatever\n                # necessary for intialisation, div by 0\n                if min(self.smiths_alpha) == max(self.smiths_alpha):\n                        alpha_range = 0.4 #starting value i guess\n                else:\n                        alpha_range = (self.smiths_alpha[-1] - min(self.smiths_alpha)) / (max(self.smiths_alpha) - min(self.smiths_alpha))\n                theta_range = self.theta_max - self.theta_min\n                desired_theta = self.theta_min + (theta_range) * (1 - alpha_range) * math.exp(gamma * (alpha_range - 1))\n                self.theta = self.theta + self.long_term_learning_rate * (desired_theta - self.theta)\n                if self.theta > self.theta_max :\n                        self.theta = self.theta_max\n                if self.theta < self.theta_min :\n                        self.theta = self.theta_min\n\n        def calcRshout(self): ## unclear in Vytelingum's paper\n                p = self.estimated_equilibrium[-1]\n                l = self.limit\n                theta = self.theta\n                if self.job == 'Bid':\n                        # Currently a buyer\n                        if l <= p: #extramarginal!\n                                self.r_shout = 0.0\n                        else: #intramarginal :(\n                                if self.buy_target > self.estimated_equilibrium[-1]:\n                                        #r[0,1]\n                                        self.r_shout = math.log(((self.buy_target - p) * (math.exp(theta) - 1) / (l - p)) + 1) / theta\n                                else:\n                                        #r[-1,0]\n                                        # print 'buy_target: %f , p: %f , theta: %f' %(self.buy_target,p,theta)\n                                        self.r_shout = math.log((1 - (self.buy_target/p)) * (math.exp(theta) - 1) + 1) / theta\n                                # self.r_shout = self.buy_r\n\n\n                if self.job == 'Ask':\n                        # Currently a seller\n                        if l >= p: #extramarginal!\n                                self.r_shout = 0\n                        else: #intramarginal :(\n                                if self.sell_target > self.estimated_equilibrium[-1]:\n                                        # r[-1,0]\n                                        self.r_shout = math.log((self.sell_target - p) * (math.exp(theta) - 1) / (self.marketMax - p) + 1) / theta\n                                else:\n                                        # r[0,1]\n                                        a = (self.sell_target-l)/(p-l)\n                                        self.r_shout = (math.log((1 - a) * (math.exp(theta) - 1) + 1)) / theta\n                                # self.r_shout = self.sell_r\n\n        def calcAgg(self):\n                delta = 0\n                if self.job == 'Bid':\n                        # BUYER\n                        if self.buy_target >= self.previous_transactions[-1] :\n                                # must be more aggressive\n                                delta = (1+self.r_shout_change_relative)*self.r_shout + self.r_shout_change_absolute\n                        else :\n                                delta = (1-self.r_shout_change_relative)*self.r_shout - self.r_shout_change_absolute\n\n                        self.buy_r = self.buy_r + self.short_term_learning_rate * (delta - self.buy_r)\n\n                if self.job == 'Ask':\n                        # SELLER\n                        if self.sell_target > self.previous_transactions[-1] :\n                                delta = (1+self.r_shout_change_relative)*self.r_shout + self.r_shout_change_absolute\n                        else :\n                                delta = (1-self.r_shout_change_relative)*self.r_shout - self.r_shout_change_absolute\n\n                        self.sell_r = self.sell_r + self.short_term_learning_rate * (delta - self.sell_r)\n\n        def calcTarget(self):\n                if len(self.estimated_equilibrium) > 0:\n                        p = self.estimated_equilibrium[-1]\n                        if self.limit == p:\n                                p = p * 1.000001 # to prevent theta_bar = 0\n                elif self.job == 'Bid':\n                        p = self.limit - self.limit * 0.2  ## Initial guess for eq if no deals yet!!....\n                elif self.job == 'Ask':\n                        p = self.limit + self.limit * 0.2\n                l = self.limit\n                theta = self.theta\n                if self.job == 'Bid':\n                        #BUYER\n                        minus_thing = self.buy_r * math.exp(theta*(self.buy_r-1))\n\n                        if l <= p: #Extramarginal\n                                if self.buy_r >= 0:\n                                        self.buy_target = l\n                                else:\n                                        self.buy_target = l * (1 - minus_thing)\n                        else: #intramarginal\n                                if self.buy_r >= 0:\n                                        # theta_ba = (p * math.exp(-theta))/(l-p)-1\n                                        theta_ba = theta\n                                        # print 'theta: %f' %(self.theta)\n                                        # print 'theta_ba: %f '%(theta_ba)\n                                        # print 'l-p: %f '%(l-p)\n                                        # print 'self.buy_r :%f' %(self.buy_r)\n\n                                        self.buy_target = (l-p)*(1-(self.buy_r+1)*math.exp(self.buy_r*theta_ba))+p\n                                else:\n                                        self.buy_target = p*(1-minus_thing)\n                        if self.buy_target > l:\n                                self.buy_target = l\n                        if self.buy_target <bse_sys_minprice :\n                                self.buy_target = bse_sys_minprice\n                        # print 'buy_target = %f'%(self.buy_target)\n\n                if self.job == 'Ask':\n                        #SELLER\n\n                        if l <= p: #Intramarginal\n                                if self.buy_r >= 0:\n                                        self.buy_target = p + (p-l)* self.sell_r*math.exp((self.sell_r-1)*theta)\n                                else:\n                                        theta_ba = math.log((self.marketMax-p)/(p-l))-theta\n                                        self.buy_target = p + (self.marketMax-p)* self.sell_r*math.exp((self.sell_r+1)*theta_ba)\n                        else: # Extramarginal\n                                if self.buy_r >= 0:\n                                        self.buy_target = l\n                                else:\n                                        self.buy_target = l + (self.marketMax-l)*self.sell_r*math.exp((self.sell_r-1)*theta)\n                        if self.sell_target < l:\n                                self.sell_target = l\n                        if self.sell_target > bse_sys_maxprice:\n                                self.sell_target = bse_sys_maxprice\n                        # print 'sell_target = %f'%(self.sell_target)\n\n        def getorder(self, time, countdown, lob,verbose):\n                if len(self.orders) < 1:\n                        self.active = False\n                        return None\n                else:\n                        self.active = True\n                        self.limit = self.orders[0].price\n                        self.job = self.orders[0].atype\n                        self.calcTarget()\n\n                        if self.prev_best_bid_p == None:\n                                o_bid = 0\n                        else:\n                                o_bid = self.prev_best_bid_p\n                        if self.prev_best_ask_p == None:\n                                o_ask = self.marketMax\n                        else:\n                                o_ask = self.prev_best_ask_p\n\n                        if self.job == 'Bid': #BUYER\n                                if self.limit <= o_bid:\n                                        return None\n                                else:\n                                        if len(self.previous_transactions) <= 0: ## has been at least one transaction\n                                                o_ask_plus = (1+self.r_shout_change_relative)*o_ask + self.r_shout_change_absolute\n                                                quoteprice = o_bid + ((min(self.limit, o_ask_plus) - o_bid) / self.offer_change_rate)\n                                        else:\n                                                if o_ask <= self.buy_target:\n                                                        quoteprice = o_ask\n                                                else:\n                                                        quoteprice = o_bid + ((self.buy_target - o_bid) / self.offer_change_rate)\n                        if self.job == 'Ask':\n                                if self.limit >= o_ask:\n                                        return None\n                                else:\n                                        if len(self.previous_transactions) <= 0: ## has been at least one transaction\n                                                o_bid_minus = (1-self.r_shout_change_relative) * o_bid - self.r_shout_change_absolute\n                                                quoteprice = o_ask - ((o_ask - max(self.limit, o_bid_minus)) / self.offer_change_rate)\n                                        else:\n                                                if o_bid >= self.sell_target:\n                                                        quoteprice = o_bid\n                                                else:\n                                                        quoteprice = o_ask - ((o_ask - self.sell_target) / self.offer_change_rate)\n                        def imbalancealter (quoteprice_aa, lob):\n                                if(lob['microprice']==None or lob['midprice']==None): return quoteprice_aa\n                                quoteprice_iaa = 0\n                                imbalance_ratio = 0\n                                volume_bids = 0\n                                volume_asks = 0\n                                count_bids_depth = 0\n                                count_asks_depth = 0\n                                for item in lob['bids']['lob']:\n                                        volume_bids += math.exp(-0.5*count_bids_depth) *item[1]\n                                        count_bids_depth +=1\n                                        if(count_bids_depth >=2): break\n                                for item in lob['asks']['lob']:\n                                        volume_asks += math.exp(-0.5*count_asks_depth) *item[1]\n                                        count_asks_depth +=1\n                                        if(count_asks_depth >=2): break\n                                if volume_bids == 0 and volume_asks == 0:\n                                        return quoteprice_aa\n                                else :\n                                        imbalance_ratio = (volume_bids-volume_asks)/(volume_bids+volume_asks)\n                                if self.job == 'Bid':\n                                        quoteprice_iaa = quoteprice_aa+imbalance_ratio*(lob['microprice']-quoteprice_aa)\n                                        if(quoteprice_iaa>self.limit):\n                                                quoteprice_iaa = self.limit\n                                else:\n                                        quoteprice_iaa = quoteprice_aa+ imbalance_ratio*(quoteprice_aa-lob['microprice'])\n                                        if(quoteprice_iaa<self.limit):\n                                                quoteprice_iaa = self.limit\n\n                                if count_bids_depth/count_asks_depth >=3 or count_asks_depth/count_bids_depth>=3 :\n                                        return  quoteprice_iaa\n                                else: return quoteprice_aa\n                                # return quoteprice_aa\n                                return quoteprice_iaa\n                        # quoteprice_iaa = imbalancealter(quoteprice,lob)\n\n                        order = Order(self.tid,\n                                    self.orders[0].atype,\n                                    'LIM',\n                                    quoteprice,\n                                    self.orders[0].qty,\n                                    time, None, -1)\n                        self.lastquote=order\n                return order\n\n        def respond(self, time, lob, trade, verbose):\n            ## Begin nicked from ZIP\n\n            # what, if anything, has happened on the bid LOB? Nicked from ZIP..\n            bid_improved = False\n            bid_hit = False\n            lob_best_bid_p = lob['bids']['bestp']\n            lob_best_bid_q = None\n            if lob_best_bid_p != None:\n                    # non-empty bid LOB\n                    lob_best_bid_q = lob['bids']['lob'][0][1]\n                    if self.prev_best_bid_p < lob_best_bid_p :\n                            # best bid has improved\n                            # NB doesn't check if the improvement was by self\n                            bid_improved = True\n                    elif trade != None and ((self.prev_best_bid_p > lob_best_bid_p) or ((self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\n                            # previous best bid was hit\n                            bid_hit = True\n            elif self.prev_best_bid_p != None:\n                    # # the bid LOB has been emptied: was it cancelled or hit?\n                    # last_tape_item = lob['tape'][-1]\n                    # if last_tape_item['type'] == 'Cancel' :\n                    #         bid_hit = False\n                    # else:\n                    #         bid_hit = True\n                    # the bid LOB is empty now but was not previously: so was it canceled or lifted?\n                    if trade != None:\n                            # a trade has occurred and the previously nonempty ask LOB is now empty\n                            # so assume best ask was lifted\n                            bid_hit = True\n                    else:\n                            bid_hit = False\n            # what, if anything, has happened on the ask LOB?\n            ask_improved = False\n            ask_lifted = False\n            lob_best_ask_p = lob['asks']['bestp']\n            lob_best_ask_q = None\n            if lob_best_ask_p != None:\n                    # non-empty ask LOB\n                    lob_best_ask_q = lob['asks']['lob'][0][1]\n                    if self.prev_best_ask_p > lob_best_ask_p :\n                            # best ask has improved -- NB doesn't check if the improvement was by self\n                            ask_improved = True\n                    elif trade != None and ((self.prev_best_ask_p < lob_best_ask_p) or ((self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\n                            # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\n                            ask_lifted = True\n            elif self.prev_best_ask_p != None:\n                    # the ask LOB is empty now but was not previously: canceled or lifted?\n                    # last_tape_item = lob['tape'][-1]\n                    # if last_tape_item['type'] == 'Cancel' :\n                    #         ask_lifted = False\n                    # else:\n                    #         ask_lifted = True\n                    # the ask LOB is empty now but was not previously: so was it canceled or lifted?\n                    if trade != None:\n                            # a trade has occurred and the previously nonempty ask LOB is now empty\n                            # so assume best ask was lifted\n                            ask_lifted = True\n                    else:\n                            ask_lifted = False\n\n            self.prev_best_bid_p = lob_best_bid_p\n            self.prev_best_bid_q = lob_best_bid_q\n            self.prev_best_ask_p = lob_best_ask_p\n            self.prev_best_ask_q = lob_best_ask_q\n\n            deal = bid_hit or ask_lifted\n\n            ## End nicked from ZIP\n\n            if deal:\n                    self.previous_transactions.append(trade['price'])\n                    if self.sell_target == None:\n                            self.sell_target = trade['price']\n                    if self.buy_target == None:\n                            self.buy_target = trade['price']\n                    self.calcEq()\n                    self.calcAlpha()\n                    self.calcTheta()\n                    self.calcRshout()\n                    self.calcAgg()\n                    self.calcTarget()\n                    #print 'sell: ', self.sell_target, 'buy: ', self.buy_target, 'limit:', self.limit, 'eq: ',  self.estimated_equilibrium[-1], 'sell_r: ', self.sell_r, 'buy_r: ', self.buy_r, '\\n'\n\n\nclass Trader_OAA(Trader):\n\n        def __init__(self, ttype, tid, balance, time):\n                # Stuff about trader\n                # self.ttype = ttype\n                # self.tid = tid\n                # self.balance = balance\n                # self.birthtime = time\n                # self.profitpertime = 0\n                # self.n_trades = 0\n                # self.blotter = []\n                # self.orders = []\n                # self.n_quotes = 0\n                # self.lastquote = None\n                Trader.__init__(self, ttype, tid, balance, time)\n\n                self.limit = None\n                self.job = None\n\n                # learning variables\n                self.r_shout_change_relative = 0.05\n                self.r_shout_change_absolute = 0.05\n                self.short_term_learning_rate = random.uniform(0.1, 0.5)\n                self.long_term_learning_rate = random.uniform(0.1, 0.5)\n                self.moving_average_weight_decay = 0.95 # how fast weight decays with time, lower is quicker, 0.9 in vytelingum\n                self.moving_average_window_size = 5\n                self.offer_change_rate = 3.0\n                self.theta = -2.0\n                self.theta_max = 2.0\n                self.theta_min = -8.0\n                self.marketMax = bse_sys_maxprice\n\n                # Variables to describe the market\n                self.previous_transactions = []\n                self.moving_average_weights = []\n                for i in range(self.moving_average_window_size):\n                        self.moving_average_weights.append(self.moving_average_weight_decay**i)\n                self.estimated_equilibrium = []\n                self.smiths_alpha = []\n                self.prev_best_bid_p = None\n                self.prev_best_bid_q = None\n                self.prev_best_ask_p = None\n                self.prev_best_ask_q = None\n\n                # Trading Variables\n                self.r_shout = None\n                self.buy_target = None\n                self.sell_target = None\n                self.buy_r = -1.0 * (0.3 * random.random())\n                self.sell_r = -1.0 * (0.3 * random.random())\n\n\n\n        def calcEq(self):\n                # Slightly modified from paper, it is unclear inpaper\n                # N previous transactions * weights / N in vytelingum, swap N denominator for sum of weights to be correct?\n                if len(self.previous_transactions) == 0:\n                        return\n                elif len(self.previous_transactions) < self.moving_average_window_size:\n                        # Not enough transactions\n                        self.estimated_equilibrium.append(float(sum(self.previous_transactions)) / max(len(self.previous_transactions), 1))\n                else:\n                        N_previous_transactions = self.previous_transactions[-self.moving_average_window_size:]\n                        thing = [N_previous_transactions[i]*self.moving_average_weights[i] for i in range(self.moving_average_window_size)]\n                        eq = sum( thing ) / sum(self.moving_average_weights)\n                        self.estimated_equilibrium.append(eq)\n\n        def calcAlpha(self):\n                alpha = 0.0\n                for p in self.estimated_equilibrium:\n                        alpha += (p - self.estimated_equilibrium[-1])**2\n                alpha = math.sqrt(alpha/len(self.estimated_equilibrium))\n                self.smiths_alpha.append( alpha/self.estimated_equilibrium[-1] )\n\n        def calcTheta(self):\n                gamma = 2.0 #not sensitive apparently so choose to be whatever\n                # necessary for intialisation, div by 0\n                if min(self.smiths_alpha) == max(self.smiths_alpha):\n                        alpha_range = 0.4 #starting value i guess\n                else:\n                        alpha_range = (self.smiths_alpha[-1] - min(self.smiths_alpha)) / (max(self.smiths_alpha) - min(self.smiths_alpha))\n                theta_range = self.theta_max - self.theta_min\n                desired_theta = self.theta_min + (theta_range) * (1 - (alpha_range * math.exp(gamma * (alpha_range - 1))))\n                self.theta = self.theta + self.long_term_learning_rate * (desired_theta - self.theta)\n\n        def calcRshout(self):\n                p = self.estimated_equilibrium[-1]\n                l = self.limit\n                theta = self.theta\n                if self.job == 'Bid':\n                        # Currently a buyer\n                        if l <= p: #extramarginal!\n                                self.r_shout = 0.0\n                        else: #intramarginal :(\n                                if self.buy_target > self.estimated_equilibrium[-1]:\n                                        #r[0,1]\n                                        self.r_shout = math.log(((self.buy_target - p) * (math.exp(theta) - 1) / (l - p)) + 1) / theta\n                                else:\n                                        #r[-1,0]\n                                        self.r_shout = math.log((1 - (self.buy_target/p)) * (math.exp(theta) - 1) + 1) / theta\n\n\n                if self.job == 'Ask':\n                        # Currently a seller\n                        if l >= p: #extramarginal!\n                                self.r_shout = 0\n                        else: #intramarginal :(\n                                if self.sell_target > self.estimated_equilibrium[-1]:\n                                        # r[-1,0]\n                                        self.r_shout = math.log((self.sell_target - p) * (math.exp(theta) - 1) / (self.marketMax - p) + 1) / theta\n                                else:\n                                        # r[0,1]\n                                        a = (self.sell_target-l)/(p-l)\n                                        self.r_shout = (math.log((1 - a) * (math.exp(theta) - 1) + 1)) / theta\n\n        def calcAgg(self):\n                delta = 0\n                if self.job == 'Bid':\n                        # BUYER\n                        if self.buy_target >= self.previous_transactions[-1] :\n                                # must be more aggressive\n                                delta = (1+self.r_shout_change_relative)*self.r_shout + self.r_shout_change_absolute\n                        else :\n                                delta = (1-self.r_shout_change_relative)*self.r_shout - self.r_shout_change_absolute\n\n                        self.buy_r = self.buy_r + self.short_term_learning_rate * (delta - self.buy_r)\n\n                if self.job == 'Ask':\n                        # SELLER\n                        if self.sell_target > self.previous_transactions[-1] :\n                                delta = (1+self.r_shout_change_relative)*self.r_shout + self.r_shout_change_absolute\n                        else :\n                                delta = (1-self.r_shout_change_relative)*self.r_shout - self.r_shout_change_absolute\n\n                        self.sell_r = self.sell_r + self.short_term_learning_rate * (delta - self.sell_r)\n\n        def calcTarget(self):\n                if len(self.estimated_equilibrium) > 0:\n                        p = self.estimated_equilibrium[-1]\n                        if self.limit == p:\n                                p = p * 1.000001 # to prevent theta_bar = 0\n                elif self.job == 'Bid':\n                        p = self.limit - self.limit * 0.2  ## Initial guess for eq if no deals yet!!....\n                elif self.job == 'Ask':\n                        p = self.limit + self.limit * 0.2\n                l = self.limit\n                theta = self.theta\n                if self.job == 'Bid':\n                        #BUYER\n                        minus_thing = (math.exp(-self.buy_r * theta) - 1) / (math.exp(theta) - 1)\n                        plus_thing = (math.exp(self.buy_r * theta) - 1) / (math.exp(theta) - 1)\n                        theta_bar = (theta * l - theta * p) / p\n                        if theta_bar == 0:\n                                theta_bar = 0.0001\n                        if math.exp(theta_bar) - 1 == 0:\n                                theta_bar = 0.0001\n                        bar_thing = (math.exp(-self.buy_r * theta_bar) - 1) / (math.exp(theta_bar) - 1)\n                        if l <= p: #Extramarginal\n                                if self.buy_r >= 0:\n                                        self.buy_target = l\n                                else:\n                                        self.buy_target = l * (1 - minus_thing)\n                        else: #intramarginal\n                                if self.buy_r >= 0:\n                                        self.buy_target = p + (l-p)*plus_thing\n                                else:\n                                        self.buy_target = p*(1-bar_thing)\n                        if self.buy_target > l:\n                                self.buy_target = l\n\n                if self.job == 'Ask':\n                        #SELLER\n                        minus_thing = (math.exp(-self.sell_r * theta) - 1) / (math.exp(theta) - 1)\n                        plus_thing = (math.exp(self.sell_r * theta) - 1) / (math.exp(theta) - 1)\n                        theta_bar = (theta * l - theta * p) / p\n                        if theta_bar == 0:\n                                theta_bar = 0.0001\n                        if math.exp(theta_bar) - 1 == 0:\n                                theta_bar = 0.0001\n                        bar_thing = (math.exp(-self.sell_r * theta_bar) - 1) / (math.exp(theta_bar) - 1) #div 0 sometimes what!?\n                        if l <= p: #Extramarginal\n                                if self.buy_r >= 0:\n                                        self.buy_target = l\n                                else:\n                                        self.buy_target = l + (self.marketMax - l)*(minus_thing)\n                        else: #intramarginal\n                                if self.buy_r >= 0:\n                                        self.buy_target = l + (p-l)*(1-plus_thing)\n                                else:\n                                        self.buy_target = p + (self.marketMax - p)*(bar_thing)\n                        if self.sell_target < l:\n                                self.sell_target = l\n\n        def getorder(self, time, countdown, lob,verbose):\n                if len(self.orders) < 1:\n                        self.active = False\n                        return None\n                else:\n                        self.active = True\n                        self.limit = self.orders[0].price\n                        self.job = self.orders[0].atype\n                        self.calcTarget()\n\n                        if self.prev_best_bid_p == None:\n                                o_bid = 0\n                        else:\n                                o_bid = self.prev_best_bid_p\n                        if self.prev_best_ask_p == None:\n                                o_ask = self.marketMax\n                        else:\n                                o_ask = self.prev_best_ask_p\n\n                        if self.job == 'Bid': #BUYER\n                                if self.limit <= o_bid:\n                                        return None\n                                else:\n                                        if len(self.previous_transactions) > 0: ## has been at least one transaction\n\n                                                o_ask_plus = (1+self.r_shout_change_relative)*o_ask + self.r_shout_change_absolute\n                                                quoteprice = o_bid + ((min(self.limit, o_ask_plus) - o_bid) / self.offer_change_rate)\n                                        else:\n\n                                                if o_ask <= self.buy_target:\n                                                        quoteprice = o_ask\n                                                else:\n                                                        quoteprice = o_bid + ((self.buy_target - o_bid) / self.offer_change_rate)\n                        if self.job == 'Ask':\n                                if self.limit >= o_ask:\n                                        return None\n                                else:\n                                        if len(self.previous_transactions) > 0: ## has been at least one transaction\n                                                o_bid_minus = (1-self.r_shout_change_relative) * o_bid - self.r_shout_change_absolute\n                                                quoteprice = o_ask - ((o_ask - max(self.limit, o_bid_minus)) / self.offer_change_rate)\n                                        else:\n                                                if o_bid >= self.sell_target:\n                                                        quoteprice = o_bid\n                                                else:\n                                                        quoteprice = o_ask - ((o_ask - self.sell_target) / self.offer_change_rate)\n\n\n                        order = Order(self.tid,\n                                    self.orders[0].atype,\n                                    'LIM',\n                                    quoteprice,\n                                    self.orders[0].qty,\n                                    time, None, -1)\n                        self.lastquote=order\n                return order\n\n        def respond(self, time, lob, trade, verbose):\n            ## Begin nicked from ZIP\n\n            # what, if anything, has happened on the bid LOB? Nicked from ZIP..\n            bid_improved = False\n            bid_hit = False\n            lob_best_bid_p = lob['bids']['bestp']\n            lob_best_bid_q = None\n            if lob_best_bid_p != None:\n                    # non-empty bid LOB\n                    lob_best_bid_q = lob['bids']['lob'][0][1]\n                    if self.prev_best_bid_p < lob_best_bid_p :\n                            # best bid has improved\n                            # NB doesn't check if the improvement was by self\n                            bid_improved = True\n                    elif trade != None and ((self.prev_best_bid_p > lob_best_bid_p) or ((self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\n                            # previous best bid was hit\n                            bid_hit = True\n            elif self.prev_best_bid_p != None:\n                    # # the bid LOB has been emptied: was it cancelled or hit?\n                    # last_tape_item = lob['tape'][-1]\n                    # if last_tape_item['type'] == 'Cancel' :\n                    #         bid_hit = False\n                    # else:\n                    #         bid_hit = True\n                    # the bid LOB is empty now but was not previously: so was it canceled or lifted?\n                    if trade != None:\n                            # a trade has occurred and the previously nonempty ask LOB is now empty\n                            # so assume best ask was lifted\n                            bid_hit = True\n                    else:\n                            bid_hit = False\n            # what, if anything, has happened on the ask LOB?\n            ask_improved = False\n            ask_lifted = False\n            lob_best_ask_p = lob['asks']['bestp']\n            lob_best_ask_q = None\n            if lob_best_ask_p != None:\n                    # non-empty ask LOB\n                    lob_best_ask_q = lob['asks']['lob'][0][1]\n                    if self.prev_best_ask_p > lob_best_ask_p :\n                            # best ask has improved -- NB doesn't check if the improvement was by self\n                            ask_improved = True\n                    elif trade != None and ((self.prev_best_ask_p < lob_best_ask_p) or ((self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\n                            # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\n                            ask_lifted = True\n            elif self.prev_best_ask_p != None:\n                    # the ask LOB is empty now but was not previously: canceled or lifted?\n                    # last_tape_item = lob['tape'][-1]\n                    # if last_tape_item['type'] == 'Cancel' :\n                    #         ask_lifted = False\n                    # else:\n                    #         ask_lifted = True\n                    # the ask LOB is empty now but was not previously: so was it canceled or lifted?\n                    if trade != None:\n                            # a trade has occurred and the previously nonempty ask LOB is now empty\n                            # so assume best ask was lifted\n                            ask_lifted = True\n                    else:\n                            ask_lifted = False\n\n            self.prev_best_bid_p = lob_best_bid_p\n            self.prev_best_bid_q = lob_best_bid_q\n            self.prev_best_ask_p = lob_best_ask_p\n            self.prev_best_ask_q = lob_best_ask_q\n\n            deal = bid_hit or ask_lifted\n\n            ## End nicked from ZIP\n\n            if deal:\n                    self.previous_transactions.append(trade['price'])\n                    if self.sell_target == None:\n                            self.sell_target = trade['price']\n                    if self.buy_target == None:\n                            self.buy_target = trade['price']\n                    self.calcEq()\n                    self.calcAlpha()\n                    self.calcTheta()\n                    self.calcRshout()\n                    self.calcAgg()\n                    self.calcTarget()\n                    #print 'sell: ', self.sell_target, 'buy: ', self.buy_target, 'limit:', self.limit, 'eq: ',  self.estimated_equilibrium[-1], 'sell_r: ', self.sell_r, 'buy_r: ', self.buy_r, '\\n'\n\nclass Trader_IAAB(Trader):\n\n        def __init__(self, ttype, tid, balance, time):\n                # Stuff about trader\n                # self.ttype = ttype\n                # self.tid = tid\n                # self.balance = balance\n                # self.birthtime = time\n                # self.profitpertime = 0\n                # self.n_trades = 0\n                # self.blotter = []\n                # self.orders = []\n                # self.n_quotes = 0\n                # self.lastquote = None\n                Trader.__init__(self, ttype, tid, balance, time)\n\n                self.limit = None\n                self.job = None\n\n                # learning variables\n                self.r_shout_change_relative = 0.05\n                self.r_shout_change_absolute = 0.05\n                self.short_term_learning_rate = random.uniform(0.1, 0.5)\n                self.long_term_learning_rate = random.uniform(0.1, 0.5)\n                self.moving_average_weight_decay = 0.95 # how fast weight decays with time, lower is quicker, 0.9 in vytelingum\n                self.moving_average_window_size = 5\n                self.offer_change_rate = 3.0\n                self.theta = -2.0\n                self.theta_max = 2.0\n                self.theta_min = -8.0\n                self.marketMax = bse_sys_maxprice\n\n                # Variables to describe the market\n                self.previous_transactions = []\n                self.moving_average_weights = []\n                for i in range(self.moving_average_window_size):\n                        self.moving_average_weights.append(self.moving_average_weight_decay**i)\n                self.estimated_equilibrium = []\n                self.smiths_alpha = []\n                self.prev_best_bid_p = None\n                self.prev_best_bid_q = None\n                self.prev_best_ask_p = None\n                self.prev_best_ask_q = None\n\n                # Trading Variables\n                self.r_shout = None\n                self.buy_target = None\n                self.sell_target = None\n                self.buy_r = -1.0 * (0.3 * random.random())\n                self.sell_r = -1.0 * (0.3 * random.random())\n\n\n                #Block order holder\n                self.remaining_quantity  = 0;\n\n\n        def add_cust_order(self, order, verbose):\n                # add a customer order to trader's records\n                # currently LAZY: keeps to within max_cust_orders by appending new order and deleting head self.orders\n                if len(self.quotes) > 0:\n                        # this trader has a live quote on the LOB, from a previous customer order\n                        # need response to signal cancellation/withdrawal of that quote\n                        response = 'LOB_Cancel'\n                else:\n                        response = 'Proceed'\n                if len(self.orders) >= self.max_cust_orders:\n                        self.orders = self.orders[1:]\n                self.orders.append(order)\n\n                self.remaining_quantity = order.qty\n\n                if verbose: print('add_order < response=%s self.orders=%s' % (response, str(self.orders)))\n                return response\n\n                # delete a customer order from trader's list of orders being worked\n\n        def del_cust_order(self, cust_order_id, verbose):\n                if verbose:\n                        print('>del_cust_order: Cust_orderID=%s; self.orders=' % cust_order_id)\n                        for o in self.orders: print('%s ' % str(o))\n\n                cust_orders = []\n                for co in self.orders:\n                        if co.assignmentid != cust_order_id: cust_orders.append(co)\n\n                self.orders = cust_orders\n\n                # revise a customer order: used after a PARTial fill on the exchange\n\n        def revise_cust_order(self, cust_order_id, revised_order, verbose):\n                if verbose:\n                        print('>revise_cust_order: Cust_orderID=%s; revised_order=%s, self.orders=' % (\n                        cust_order_id, revised_order))\n                        for o in self.orders: print('%s ' % str(o))\n\n                cust_orders = []\n                for co in self.orders:\n                        if co.assignmentid != cust_order_id:\n                                cust_orders.append(co)\n                        else:\n                                revised_assignment = co\n                                revised_assignment.qty = self.remaining_quantity\n                                cust_orders.append(revised_assignment)\n\n                self.orders = cust_orders\n\n                if verbose:\n                        print('<revise_cust_order: Cust_orderID=%s; revised_order=%s, self.orders=' % (\n                        cust_order_id, revised_order))\n                        for o in self.orders: print('%s ' % str(o))\n\n                # delete an order/quote from the trader's list of its orders live on the exchange\n\n        def del_exch_order(self, oid, verbose):\n                if verbose:\n                        print('>del_exch_order: OID:%d; self.quotes=' % oid)\n                        for q in self.quotes: print('%s ' % str(q))\n\n                exch_orders = []\n                for eo in self.quotes:\n                        if eo.orderid != oid: exch_orders.append(eo)\n\n                self.quotes = exch_orders\n\n        def bookkeep(self, msg, time, verbose):\n                # bookkeep(): trader book-keeping in response to message from the exchange\n                # update records of what orders are still being worked, account balance, etc.\n                # trader's blotter is a simple sequential record of each exchange messages received, and the trader's balance after bookeeping that msh\n\n                if verbose: print('>bookkeep msg=%s bal=%d' % (msg, self.balance))\n\n                profit = 0\n\n                if msg.event == \"CAN\":\n                        # order was cancelled at the exchange\n                        # so delete the order from the trader's records of what quotes it has live on the exchange\n                        if verbose:\n                                print(\">CANcellation: msg=%s quotes=\" % str(msg))\n                                for q in self.quotes: print(\"%s\" % str(q))\n\n                        newquotes = []\n                        for q in self.quotes:\n                                if q.orderid != msg.oid:\n                                        newquotes.append(q)\n                        self.quotes = newquotes\n\n                        if verbose:\n                                print(\"<CANcellation: quotes=\")\n                                for q in self.quotes: print(\"%s\" % str(q))\n\n                # an individual order of some types (e.g. MKT) can fill via transactions at different prices\n                # so the message that comes back from the exchange has transaction data in a list: will often be length=1\n\n                if msg.event == \"FILL\" or msg.event == \"PART\":\n\n                        for trans in msg.trns:\n                                transactionprice = trans[\"Price\"]\n                                qty = trans[\"Qty\"]\n\n\n                                self. remaining_quantity = self.remaining_quantity - qty;\n\n\n                                # find this LOB order in the trader's list of quotes sent to exchange\n                                exch_order = None\n                                for ord in self.quotes:\n                                        if ord.orderid == msg.oid:\n                                                exch_order = ord\n                                        break\n                                if exch_order == None:\n                                        s = 'FAIL: bookkeep() cant find order (msg.oid=%d) orders=' % msg.oid\n                                        for ord in self.quotes: s = s + str(ord)\n                                        sys.exit(s)\n\n                                cust_order_id = exch_order.myref\n                                cust_order = None\n                                for assignment in self.orders:\n                                        if assignment.assignmentid == cust_order_id:\n                                                cust_order = assignment\n                                                break\n\n                                limitprice = cust_order.price\n\n                                if exch_order.otype == 'Bid':\n                                        profit = (limitprice - transactionprice) * qty\n                                else:\n                                        profit = (transactionprice - limitprice) * qty\n\n\n                                self.balance += profit\n\n                                print 'IAAB\\'s transaction quantity = '\n                                print qty\n                                print 'IAAB\\'s transaction price = '\n                                print transactionprice\n                                print 'IAAB\\'s profit = '\n                                print profit\n                                print 'IAAB\\'s balance = '\n                                print self.balance\n                                print 'IAAB\\'s remaining quantity = '\n                                print self.remaining_quantity\n\n\n\n                                self.n_trades += 1\n                                age = time - self.birthtime\n                                self.profitpertime = self.balance / age\n\n                                if verbose: print('Price=%d Limit=%d Q=%d Profit=%d N_trades=%d Age=%f Balance=%d' %\n                                                  (transactionprice, limitprice, qty, profit, self.n_trades, age,\n                                                   self.balance))\n\n                                if profit < 0:\n                                        print self.tid\n                                        print self.ttype\n                                        print profit\n                                        print exch_order\n                                        sys.exit('Exit: Negative profit')\n\n                        if verbose: print('%s: profit=%d bal=%d profit/time=%f' %\n                                          (self.tid, profit, self.balance, self.profitpertime))\n\n                        # by the time we get to here, exch_order is instantiated\n                        cust_order_id = exch_order.myref\n\n                        if msg.event == \"FILL\":\n                                # this order has completed in full, so it thereby completes the corresponding customer order\n                                # so delete both the customer order from trader's record of those\n                                # and the order has already been deleted from the exchange's records, so also needs to be deleted from trader's records of orders held at exchange\n                                cust_order_id = exch_order.myref\n\n                                if(self.remaining_quantity<=0):\n                                        self.del_cust_order(cust_order_id, verbose)  # delete this customer order\n\n\n\n\n                                self.del_exch_order(exch_order.orderid,\n                                                    verbose)  # delete the exchange-order from trader's records\n\n                        elif msg.event == \"PART\":\n                                # the customer order is still live, but its quantity needs updating\n                                if verbose: print(\n                                                '>bookkeep() PART-filled order updating qty on customer order ID=%s' % cust_order_id)\n                                self.revise_cust_order(cust_order_id, msg.revo, verbose)  # delete this customer order\n\n                                if exch_order.ostyle == \"IOC\":\n                                        # a partially filled IOC has the non-filled portion cancelled at the exchange,\n                                        # so the trader's order records need to be updated accordingly\n                                        if verbose: print(\n                                                        \">bookkeep() PART-filled IOC cancels remainder: deleting OID:%d from trader's exchange-order records\" % exch_order.orderid)\n                                        self.del_exch_order(exch_order.orderid,\n                                                            verbose)  # delete the exchange-order from trader's records\n\n                self.blotter.append([msg, self.balance])  # add trade record to trader's blotter\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n        def calcEq(self): ##clear and correct\n                # Slightly modified from paper, it is unclear inpaper\n                # N previous transactions * weights / N in vytelingum, swap N denominator for sum of weights to be correct?\n                if len(self.previous_transactions) == 0:\n                        return\n                elif len(self.previous_transactions) < self.moving_average_window_size:\n                        # Not enough transactions\n                        self.estimated_equilibrium.append(float(sum(self.previous_transactions)) / max(len(self.previous_transactions), 1))\n                else:\n                        N_previous_transactions = self.previous_transactions[-self.moving_average_window_size:]\n                        thing = [N_previous_transactions[i]*self.moving_average_weights[i] for i in range(self.moving_average_window_size)]\n                        eq = sum( thing ) / sum(self.moving_average_weights)\n                        self.estimated_equilibrium.append(eq)\n\n        def calcAlpha(self): ##correct. but calcAlpha in snashall's version is incorrect\n                alpha = 0.0\n                for p in self.previous_transactions:\n                        alpha += (p - self.estimated_equilibrium[-1])**2\n                alpha = math.sqrt(alpha/len(self.previous_transactions))\n                self.smiths_alpha.append( alpha/self.estimated_equilibrium[-1] )\n\n        def calcTheta(self): ## clear and correct\n                gamma = 2.0 #not sensitive apparently so choose to be whatever\n                # necessary for intialisation, div by 0\n                if min(self.smiths_alpha) == max(self.smiths_alpha):\n                        alpha_range = 0.4 #starting value i guess\n                else:\n                        alpha_range = (self.smiths_alpha[-1] - min(self.smiths_alpha)) / (max(self.smiths_alpha) - min(self.smiths_alpha))\n                theta_range = self.theta_max - self.theta_min\n                desired_theta = self.theta_min + (theta_range) * (1 - alpha_range) * math.exp(gamma * (alpha_range - 1))\n                self.theta = self.theta + self.long_term_learning_rate * (desired_theta - self.theta)\n                if self.theta > self.theta_max :\n                        self.theta = self.theta_max\n                if self.theta < self.theta_min :\n                        self.theta = self.theta_min\n\n        def calcRshout(self): ## unclear in Vytelingum's paper\n                p = self.estimated_equilibrium[-1]\n                l = self.limit\n                theta = self.theta\n                if self.job == 'Bid':\n                        # Currently a buyer\n                        if l <= p: #extramarginal!\n                                self.r_shout = 0.0\n                        else: #intramarginal :(\n                                if self.buy_target > self.estimated_equilibrium[-1]:\n                                        #r[0,1]\n                                        self.r_shout = math.log(((self.buy_target - p) * (math.exp(theta) - 1) / (l - p)) + 1) / theta\n                                else:\n                                        #r[-1,0]\n                                        # print 'buy_target: %f , p: %f , theta: %f' %(self.buy_target,p,theta)\n                                        self.r_shout = math.log((1 - (self.buy_target/p)) * (math.exp(theta) - 1) + 1) / theta\n                                # self.r_shout = self.buy_r\n\n\n                if self.job == 'Ask':\n                        # Currently a seller\n                        if l >= p: #extramarginal!\n                                self.r_shout = 0\n                        else: #intramarginal :(\n                                if self.sell_target > self.estimated_equilibrium[-1]:\n                                        # r[-1,0]\n                                        self.r_shout = math.log((self.sell_target - p) * (math.exp(theta) - 1) / (self.marketMax - p) + 1) / theta\n                                else:\n                                        # r[0,1]\n                                        a = (self.sell_target-l)/(p-l)\n                                        self.r_shout = (math.log((1 - a) * (math.exp(theta) - 1) + 1)) / theta\n                                # self.r_shout = self.sell_r\n\n        def calcAgg(self):\n                delta = 0\n                if self.job == 'Bid':\n                        # BUYER\n                        if self.buy_target >= self.previous_transactions[-1] :\n                                # must be more aggressive\n                                delta = (1+self.r_shout_change_relative)*self.r_shout + self.r_shout_change_absolute\n                        else :\n                                delta = (1-self.r_shout_change_relative)*self.r_shout - self.r_shout_change_absolute\n\n                        self.buy_r = self.buy_r + self.short_term_learning_rate * (delta - self.buy_r)\n\n                if self.job == 'Ask':\n                        # SELLER\n                        if self.sell_target > self.previous_transactions[-1] :\n                                delta = (1+self.r_shout_change_relative)*self.r_shout + self.r_shout_change_absolute\n                        else :\n                                delta = (1-self.r_shout_change_relative)*self.r_shout - self.r_shout_change_absolute\n\n                        self.sell_r = self.sell_r + self.short_term_learning_rate * (delta - self.sell_r)\n\n        def calcTarget(self):\n                if len(self.estimated_equilibrium) > 0:\n                        p = self.estimated_equilibrium[-1]\n                        if self.limit == p:\n                                p = p * 1.000001 # to prevent theta_bar = 0\n                elif self.job == 'Bid':\n                        p = self.limit - self.limit * 0.2  ## Initial guess for eq if no deals yet!!....\n                elif self.job == 'Ask':\n                        p = self.limit + self.limit * 0.2\n                l = self.limit\n                theta = self.theta\n                if self.job == 'Bid':\n                        #BUYER\n                        minus_thing = self.buy_r * math.exp(theta*(self.buy_r-1))\n\n                        if l <= p: #Extramarginal\n                                if self.buy_r >= 0:\n                                        self.buy_target = l\n                                else:\n                                        self.buy_target = l * (1 - minus_thing)\n                        else: #intramarginal\n                                if self.buy_r >= 0:\n                                        # theta_ba = (p * math.exp(-theta))/(l-p)-1\n                                        theta_ba = theta\n                                        # print 'theta: %f' %(self.theta)\n                                        # print 'theta_ba: %f '%(theta_ba)\n                                        # print 'l-p: %f '%(l-p)\n                                        # print 'self.buy_r :%f' %(self.buy_r)\n\n                                        self.buy_target = (l-p)*(1-(self.buy_r+1)*math.exp(self.buy_r*theta_ba))+p\n                                else:\n                                        self.buy_target = p*(1-minus_thing)\n                        if self.buy_target > l:\n                                self.buy_target = l\n                        if self.buy_target <bse_sys_minprice :\n                                self.buy_target = bse_sys_minprice\n                        # print 'buy_target = %f'%(self.buy_target)\n\n                if self.job == 'Ask':\n                        #SELLER\n\n                        if l <= p: #Intramarginal\n                                if self.buy_r >= 0:\n                                        self.buy_target = p + (p-l)* self.sell_r*math.exp((self.sell_r-1)*theta)\n                                else:\n                                        theta_ba = math.log((self.marketMax-p)/(p-l))-theta\n                                        self.buy_target = p + (self.marketMax-p)* self.sell_r*math.exp((self.sell_r+1)*theta_ba)\n                        else: # Extramarginal\n                                if self.buy_r >= 0:\n                                        self.buy_target = l\n                                else:\n                                        self.buy_target = l + (self.marketMax-l)*self.sell_r*math.exp((self.sell_r-1)*theta)\n                        if self.sell_target < l:\n                                self.sell_target = l\n                        if self.sell_target > bse_sys_maxprice:\n                                self.sell_target = bse_sys_maxprice\n                        # print 'sell_target = %f'%(self.sell_target)\n\n        def getorder(self, time, countdown, lob,verbose):\n                if len(self.orders) < 1:\n                        self.active = False\n                        return None\n                else:\n                        self.active = True\n                        self.limit = self.orders[0].price\n                        self.job = self.orders[0].atype\n                        self.calcTarget()\n\n                        if self.prev_best_bid_p == None:\n                                o_bid = 0\n                        else:\n                                o_bid = self.prev_best_bid_p\n                        if self.prev_best_ask_p == None:\n                                o_ask = self.marketMax\n                        else:\n                                o_ask = self.prev_best_ask_p\n\n                        if self.job == 'Bid': #BUYER\n                                if self.limit <= o_bid:\n                                        return None\n                                else:\n                                        if len(self.previous_transactions) > 0: ## has been at least one transaction\n                                                o_ask_plus = (1+self.r_shout_change_relative)*o_ask + self.r_shout_change_absolute\n                                                quoteprice = o_bid + ((min(self.limit, o_ask_plus) - o_bid) / self.offer_change_rate)\n                                        else:\n                                                if o_ask <= self.buy_target:\n                                                        quoteprice = o_ask\n                                                else:\n                                                        quoteprice = o_bid + ((self.buy_target - o_bid) / self.offer_change_rate)\n                        if self.job == 'Ask':\n                                if self.limit >= o_ask:\n                                        return None\n                                else:\n                                        if len(self.previous_transactions) <= 0: ## has been at least one transaction\n                                                o_bid_minus = (1-self.r_shout_change_relative) * o_bid - self.r_shout_change_absolute\n                                                quoteprice = o_ask - ((o_ask - max(self.limit, o_bid_minus)) / self.offer_change_rate)\n                                        else:\n                                                if o_bid >= self.sell_target:\n                                                        quoteprice = o_bid\n                                                else:\n                                                        quoteprice = o_ask - ((o_ask - self.sell_target) / self.offer_change_rate)\n                        def imbalance_alter (quoteprice_aa, lob):\n\n                                if(lob['microprice']==None or lob['midprice']==None):\n                                        return quoteprice_aa\n\n                                quoteprice_iaa = 0\n                                imbalance_ratio = 0\n                                # the measurement of size in demand side\n                                volume_bids = 0\n                                # the measurement of size in supply side\n                                volume_asks = 0\n                                #the depth of lob, how many different price.\n                                count_bids_depth = 0\n                                count_asks_depth = 0\n                                for item in lob['bids']['lob']:\n                                        volume_bids += math.exp(-0.5*count_bids_depth) *item[1]\n                                        count_bids_depth +=1\n                                        #only consider the first 3 quota\n                                        if(count_bids_depth >=3): break\n                                for item in lob['asks']['lob']:\n                                        volume_asks += math.exp(-0.5*count_asks_depth) *item[1]\n                                        count_asks_depth +=1\n                                        #only consider the first 3 quota\n                                        if(count_asks_depth >=3): break\n                                #lob is none\n                                if volume_bids == 0 and volume_asks == 0:\n                                        return quoteprice_aa\n                                else :\n                                        # imbalance_ratio will be treated as learning rate in widrow\n                                        imbalance_ratio = (volume_bids-volume_asks)/(volume_bids+volume_asks)\n                                if self.job == 'Bid':\n                                        quoteprice_iaa = quoteprice_aa+imbalance_ratio*(lob['microprice']-lob['midprice'])\n                                        if(quoteprice_iaa>self.limit):\n                                                quoteprice_iaa = self.limit\n                                else:\n                                        quoteprice_iaa = quoteprice_aa+ imbalance_ratio*(lob['microprice']-lob['midprice'])\n                                        if(quoteprice_iaa<self.limit):\n                                                quoteprice_iaa = self.limit\n                                # return quoteprice_aa\n                                # if count_bids_depth/count_asks_depth >=3 or count_asks_depth/count_bids_depth>=3 :\n                                #         return  quoteprice_iaa\n                                # else: return quoteprice_aa\n                                # # return quoteprice_aa\n                                # print 'depth_bids: %f' %(count_bids_depth)\n                                # print 'depth_asks: %f' %(count_asks_depth)\n                                # print 'volume_bids: %f' %(volume_bids)\n                                # print 'volume_asks: %f' %(volume_asks)\n                                # print 'imbalance ratio: %f' %(imbalance_ratio)\n                                # print 'IAA original quotaprice: %d' % (quoteprice_aa)\n                                # print 'IAA final quotaprice: %d' % (quoteprice_iaa)\n                                return quoteprice_iaa\n\n                        quoteprice_iaa = imbalance_alter(quoteprice,lob)\n\n                        def divide_block_order ():\n                            return min(random.randint(1,3),self.remaining_quantity)\n                        order = Order(self.tid,\n                                    self.orders[0].atype,\n                                    'LIM',\n                                    quoteprice_iaa,\n                                    divide_block_order(),\n                                    time, None, -1)\n                        self.lastquote=order\n\n                        print 'IAAB deal with block order'\n                        print str(order)\n                return order\n\n        def respond(self, time, lob, trade, verbose):\n            ## Begin nicked from ZIP\n\n            # what, if anything, has happened on the bid LOB? Nicked from ZIP..\n            bid_improved = False\n            bid_hit = False\n            lob_best_bid_p = lob['bids']['bestp']\n            lob_best_bid_q = None\n            if lob_best_bid_p != None:\n                    # non-empty bid LOB\n                    lob_best_bid_q = lob['bids']['lob'][0][1]\n                    if self.prev_best_bid_p < lob_best_bid_p :\n                            # best bid has improved\n                            # NB doesn't check if the improvement was by self\n                            bid_improved = True\n                    elif trade != None and ((self.prev_best_bid_p > lob_best_bid_p) or ((self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\n                            # previous best bid was hit\n                            bid_hit = True\n            elif self.prev_best_bid_p != None:\n                    # # the bid LOB has been emptied: was it cancelled or hit?\n                    # last_tape_item = lob['tape'][-1]\n                    # if last_tape_item['type'] == 'Cancel' :\n                    #         bid_hit = False\n                    # else:\n                    #         bid_hit = True\n                    # the bid LOB is empty now but was not previously: so was it canceled or lifted?\n                    if trade != None:\n                            # a trade has occurred and the previously nonempty ask LOB is now empty\n                            # so assume best ask was lifted\n                            bid_hit = True\n                    else:\n                            bid_hit = False\n            # what, if anything, has happened on the ask LOB?\n            ask_improved = False\n            ask_lifted = False\n            lob_best_ask_p = lob['asks']['bestp']\n            lob_best_ask_q = None\n            if lob_best_ask_p != None:\n                    # non-empty ask LOB\n                    lob_best_ask_q = lob['asks']['lob'][0][1]\n                    if self.prev_best_ask_p > lob_best_ask_p :\n                            # best ask has improved -- NB doesn't check if the improvement was by self\n                            ask_improved = True\n                    elif trade != None and ((self.prev_best_ask_p < lob_best_ask_p) or ((self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\n                            # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\n                            ask_lifted = True\n            elif self.prev_best_ask_p != None:\n                    # the ask LOB is empty now but was not previously: canceled or lifted?\n                    # last_tape_item = lob['tape'][-1]\n                    # if last_tape_item['type'] == 'Cancel' :\n                    #         ask_lifted = False\n                    # else:\n                    #         ask_lifted = True\n                    # the ask LOB is empty now but was not previously: so was it canceled or lifted?\n                    if trade != None:\n                            # a trade has occurred and the previously nonempty ask LOB is now empty\n                            # so assume best ask was lifted\n                            ask_lifted = True\n                    else:\n                            ask_lifted = False\n\n            self.prev_best_bid_p = lob_best_bid_p\n            self.prev_best_bid_q = lob_best_bid_q\n            self.prev_best_ask_p = lob_best_ask_p\n            self.prev_best_ask_q = lob_best_ask_q\n\n            deal = bid_hit or ask_lifted\n\n            ## End nicked from ZIP\n\n            if deal:\n                    self.previous_transactions.append(trade['price'])\n                    if self.sell_target == None:\n                            self.sell_target = trade['price']\n                    if self.buy_target == None:\n                            self.buy_target = trade['price']\n                    self.calcEq()\n                    self.calcAlpha()\n                    self.calcTheta()\n                    self.calcRshout()\n                    self.calcAgg()\n                    self.calcTarget()\n                    #print 'sell: ', self.sell_target, 'buy: ', self.buy_target, 'limit:', self.limit, 'eq: ',  self.estimated_equilibrium[-1], 'sell_r: ', self.sell_r, 'buy_r: ', self.buy_r, '\\n'\n\n\n"
  },
  {
    "path": "ZhenZhang/source/GDX.py",
    "content": "# Trader subclass ZIP\r\n# After Cliff 1997\r\n\r\n\r\nfrom BSE2_msg_classes import Assignment, Order, Exch_msg\r\nfrom BSE_trader_agents import Trader;\r\nimport random\r\nimport math\r\n\r\nbse_sys_minprice = 1  # minimum price in the system, in cents/pennies\r\nbse_sys_maxprice = 200  # maximum price in the system, in cents/pennies\r\n\r\nclass Trader_GDX(Trader):\r\n\r\n        def __init__(self, ttype, tid, balance, time):\r\n                Trader.__init__(self, ttype, tid, balance, time)\r\n                self.prev_orders = []\r\n                self.active = False\r\n                self.limit = None\r\n                self.job = None\r\n\r\n\r\n\r\n                #memory of all bids and asks and accepted bids and asks\r\n                self.outstanding_bids = []\r\n                self.outstanding_asks = []\r\n                self.accepted_asks = []\r\n                self.accepted_bids = []\r\n\r\n                self.price = -1\r\n\r\n                # memory of best price & quantity of best bid and ask, on LOB on previous update\r\n                self.prev_best_bid_p = None\r\n                self.prev_best_bid_q = None\r\n                self.prev_best_ask_p = None\r\n                self.prev_best_ask_q = None\r\n\r\n                self.first_turn = True\r\n\r\n                self.gamma = 0.1\r\n\r\n                self.holdings = 10\r\n                self.remaining_offer_ops = 10\r\n                self.values = [[0 for n in range(self.remaining_offer_ops)] for m in range(self.holdings)]\r\n\r\n\r\n        def getorder(self, time, countdown, lob, verbose):\r\n                if len(self.orders) < 1:\r\n                        self.active = False\r\n                        order = None\r\n                else:\r\n                        self.active = True\r\n                        self.limit = self.orders[0].price\r\n                        self.job = self.orders[0].atype\r\n\r\n                        #calculate price\r\n                        if self.job == 'Bid':\r\n                                self.price = self.calc_p_bid(self.holdings - 1, self.remaining_offer_ops - 1)\r\n                        if self.job == 'Ask':\r\n                                self.price = self.calc_p_ask(self.holdings - 1, self.remaining_offer_ops - 1)\r\n\r\n                        order = Order(self.tid, self.job, 'LIM',self.price, self.orders[0].qty, time, None,  -1)\r\n                        self.lastquote = order\r\n\r\n                if self.first_turn or self.price == -1:\r\n                        if self.job == 'Bid':\r\n                                order = Order(self.tid, self.job, 'LIM',bse_sys_minprice+1 , self.orders[0].qty, time, None, -1)\r\n                        if self.job == 'Ask':\r\n                                order = Order(self.tid, self.job, 'LIM',bse_sys_maxprice-1 , self.orders[0].qty, time, None, -1)\r\n\r\n\r\n                return order\r\n\r\n        def calc_p_bid(self, m, n):\r\n                best_return = 0\r\n                best_bid = 0\r\n                second_best_return = 0\r\n                second_best_bid = 0\r\n\r\n                #first step size of 1 get best and 2nd best\r\n                for i in [x*2 for x in range(int(self.limit/2))]:\r\n                        thing = self.belief_buy(i) * ((self.limit - i) + self.gamma*self.values[m-1][n-1]) + (1-self.belief_buy(i) * self.gamma * self.values[m][n-1])\r\n                        if thing > best_return:\r\n                                second_best_bid = best_bid\r\n                                second_best_return = best_return\r\n                                best_return = thing\r\n                                best_bid = i\r\n\r\n                #always best bid largest one\r\n                if second_best_bid > best_bid:\r\n                        a = second_best_bid\r\n                        second_best_bid = best_bid\r\n                        best_bid = a\r\n\r\n                #then step size 0.05\r\n                for i in [x*0.05 for x in range(int(second_best_bid), int(best_bid))]:\r\n                        thing = self.belief_buy(i + second_best_bid) * ((self.limit - (i + second_best_bid)) + self.gamma*self.values[m-1][n-1]) + (1-self.belief_buy(i + second_best_bid) * self.gamma * self.values[m][n-1])\r\n                        if thing > best_return:\r\n                                best_return = thing\r\n                                best_bid = i + second_best_bid\r\n\r\n                return best_bid\r\n\r\n        def calc_p_ask(self, m, n):\r\n                best_return = 0\r\n                best_ask = self.limit\r\n                second_best_return = 0\r\n                second_best_ask = self.limit\r\n\r\n                #first step size of 1 get best and 2nd best\r\n                for i in [x*2 for x in range(int(self.limit/2))]:\r\n                        j = i + self.limit\r\n                        thing =  self.belief_sell(j) * ((j - self.limit) + self.gamma*self.values[m-1][n-1]) + (1-self.belief_sell(j) * self.gamma * self.values[m][n-1])\r\n                        if thing > best_return:\r\n                                second_best_ask = best_ask\r\n                                second_best_return = best_return\r\n                                best_return = thing\r\n                                best_ask = j\r\n                #always best ask largest one\r\n                if second_best_ask > best_ask:\r\n                        a = second_best_ask\r\n                        second_best_ask = best_ask\r\n                        best_ask = a\r\n\r\n                #then step size 0.05\r\n                for i in [x*0.05 for x in range(int(second_best_ask), int(best_ask))]:\r\n                        thing = self.belief_sell(i + second_best_ask) * (((i + second_best_ask) - self.limit) + self.gamma*self.values[m-1][n-1]) + (1-self.belief_sell(i + second_best_ask) * self.gamma * self.values[m][n-1])\r\n                        if thing > best_return:\r\n                                best_return = thing\r\n                                best_ask = i + second_best_ask\r\n\r\n                return best_ask\r\n\r\n        def belief_sell(self, price):\r\n                accepted_asks_greater = 0\r\n                bids_greater = 0\r\n                unaccepted_asks_lower = 0\r\n                for p in self.accepted_asks:\r\n                        if p >= price:\r\n                                accepted_asks_greater += 1\r\n                for p in [thing[0] for thing in self.outstanding_bids]:\r\n                        if p >= price:\r\n                                bids_greater += 1\r\n                for p in [thing[0] for thing in self.outstanding_asks]:\r\n                        if p <= price:\r\n                                unaccepted_asks_lower += 1\r\n\r\n                if accepted_asks_greater + bids_greater + unaccepted_asks_lower == 0:\r\n                        return 0\r\n                return (accepted_asks_greater + bids_greater) / (accepted_asks_greater + bids_greater + unaccepted_asks_lower)\r\n\r\n        def belief_buy(self, price):\r\n                accepted_bids_lower = 0\r\n                asks_lower = 0\r\n                unaccepted_bids_greater = 0\r\n                for p in self.accepted_bids:\r\n                        if p <= price:\r\n                                accepted_bids_lower += 1\r\n                for p in [thing[0] for thing in self.outstanding_asks]:\r\n                        if p <= price:\r\n                                asks_lower += 1\r\n                for p in [thing[0] for thing in self.outstanding_bids]:\r\n                        if p >= price:\r\n                                unaccepted_bids_greater += 1\r\n                if accepted_bids_lower + asks_lower + unaccepted_bids_greater == 0:\r\n                        return 0\r\n                return (accepted_bids_lower + asks_lower) / (accepted_bids_lower + asks_lower + unaccepted_bids_greater)\r\n\r\n        def respond(self, time, lob, trade, verbose):\r\n                # what, if anything, has happened on the bid LOB?\r\n                self.outstanding_bids = lob['bids']['lob']\r\n                bid_improved = False\r\n                bid_hit = False\r\n                lob_best_bid_p = lob['bids']['bestp']\r\n                lob_best_bid_q = None\r\n                if lob_best_bid_p != None:\r\n                        # non-empty bid LOB\r\n                        lob_best_bid_q = lob['bids']['lob'][-1][1]\r\n                        if self.prev_best_bid_p < lob_best_bid_p :\r\n                                # best bid has improved\r\n                                # NB doesn't check if the improvement was by self\r\n                                bid_improved = True\r\n                        elif trade != None and ((self.prev_best_bid_p > lob_best_bid_p) or ((self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\r\n                                # previous best bid was hit\r\n                                self.accepted_bids.append(self.prev_best_bid_p)\r\n                                bid_hit = True\r\n                elif self.prev_best_bid_p != None:\r\n                        # the bid LOB has been emptied: was it cancelled or hit?\r\n                        last_tape_item = lob['tape'][-1]\r\n                        if last_tape_item['type'] == 'Cancel' :\r\n                                bid_hit = False\r\n                        else:\r\n                                bid_hit = True\r\n\r\n                # what, if anything, has happened on the ask LOB?\r\n                self.outstanding_asks = lob['asks']['lob']\r\n                ask_improved = False\r\n                ask_lifted = False\r\n                lob_best_ask_p = lob['asks']['bestp']\r\n                lob_best_ask_q = None\r\n                if lob_best_ask_p != None:\r\n                        # non-empty ask LOB\r\n                        lob_best_ask_q = lob['asks']['lob'][0][1]\r\n                        if self.prev_best_ask_p > lob_best_ask_p :\r\n                                # best ask has improved -- NB doesn't check if the improvement was by self\r\n                                ask_improved = True\r\n                        elif trade != None and ((self.prev_best_ask_p < lob_best_ask_p) or ((self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\r\n                                # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\r\n                                self.accepted_asks.append(self.prev_best_ask_p)\r\n                                ask_lifted = True\r\n                elif self.prev_best_ask_p != None:\r\n                        # the ask LOB is empty now but was not previously: canceled or lifted?\r\n                        last_tape_item = lob['tape'][-1]\r\n                        if last_tape_item['type'] == 'Cancel' :\r\n                                ask_lifted = False\r\n                        else:\r\n                                ask_lifted = True\r\n\r\n\r\n                #populate expected values\r\n                if self.first_turn:\r\n                        # print \"populating\"\r\n                        self.first_turn = False\r\n                        for n in range(1, self.remaining_offer_ops):\r\n                                for m in range(1, self.holdings):\r\n                                            if self.job == 'Bid':\r\n                                                    #BUYER\r\n                                                    self.values[m][n] = self.calc_p_bid(m, n)\r\n\r\n                                            if self.job == 'Ask':\r\n                                                    #BUYER\r\n                                                    self.values[m][n] = self.calc_p_ask(m, n)\r\n                        # print \"done\"\r\n\r\n\r\n                deal = bid_hit or ask_lifted\r\n\r\n\r\n                # remember the best LOB data ready for next response\r\n                self.prev_best_bid_p = lob_best_bid_p\r\n                self.prev_best_bid_q = lob_best_bid_q\r\n                self.prev_best_ask_p = lob_best_ask_p\r\n                self.prev_best_ask_q = lob_best_ask_q\r\n\r\n"
  },
  {
    "path": "ZhenZhang/source/IAA_MLOFI.py",
    "content": "\r\nfrom BSE2_msg_classes import Assignment, Order, Exch_msg\r\nfrom BSE_trader_agents import Trader;\r\nimport random\r\nimport math\r\n\r\nbse_sys_minprice = 1  # minimum price in the system, in cents/pennies\r\nbse_sys_maxprice = 200  # maximum price in the system, in cents/pennies\r\n\r\n\r\nclass Trader_IAA_MLOFI(Trader):\r\n\r\n    def __init__(self, ttype, tid, balance, time,m):\r\n\r\n        Trader.__init__(self, ttype, tid, balance, time)\r\n\r\n        self.limit = None\r\n        self.job = None\r\n\r\n        # learning variables\r\n        self.r_shout_change_relative = 0.05\r\n        self.r_shout_change_absolute = 0.05\r\n        self.short_term_learning_rate = random.uniform(0.1, 0.5)\r\n        self.long_term_learning_rate = random.uniform(0.1, 0.5)\r\n        self.moving_average_weight_decay = 0.95  # how fast weight decays with time, lower is quicker, 0.9 in vytelingum\r\n        self.moving_average_window_size = 5\r\n        self.offer_change_rate = 3.0\r\n        self.theta = -2.0\r\n        self.theta_max = 2.0\r\n        self.theta_min = -8.0\r\n        self.marketMax = bse_sys_maxprice\r\n\r\n        # Variables to describe the market\r\n        self.previous_transactions = []\r\n        self.moving_average_weights = []\r\n        for i in range(self.moving_average_window_size):\r\n            self.moving_average_weights.append(self.moving_average_weight_decay ** i)\r\n        self.estimated_equilibrium = []\r\n        self.smiths_alpha = []\r\n        self.prev_best_bid_p = None\r\n        self.prev_best_bid_q = None\r\n        self.prev_best_ask_p = None\r\n        self.prev_best_ask_q = None\r\n\r\n        # Trading Variables\r\n        self.r_shout = None\r\n        self.buy_target = None\r\n        self.sell_target = None\r\n        self.buy_r = -1.0 * (0.3 * random.random())\r\n        self.sell_r = -1.0 * (0.3 * random.random())\r\n\r\n        # variable for MLOFI\r\n        self.last_lob = None;\r\n        self.es_list = [];\r\n        self.ds_list = [];\r\n\r\n        #variable\r\n        self.m = m;\r\n\r\n\r\n\r\n    def calc_level_n_e(self, current_lob, n):\r\n        b_n = 0\r\n        r_n = 0\r\n        a_n = 0\r\n        q_n = 0\r\n\r\n        b_n_1 = 0\r\n        r_n_1 = 0\r\n        a_n_1 = 0\r\n        q_n_1 = 0\r\n\r\n        if (len(current_lob['bids']['lob']) < n):\r\n            b_n = 0\r\n            r_n = 0\r\n        else:\r\n            b_n = current_lob['bids']['lob'][n - 1][0]\r\n            r_n = current_lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(self.last_lob['bids']['lob']) < n):\r\n            b_n_1 = 0\r\n            r_n_1 = 0\r\n        else:\r\n            b_n_1 = self.last_lob['bids']['lob'][n - 1][0]\r\n            r_n_1 = self.last_lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(current_lob['asks']['lob']) < n):\r\n            a_n = 0\r\n            q_n = 0\r\n        else:\r\n            a_n = current_lob['asks']['lob'][n - 1][0]\r\n            q_n = current_lob['asks']['lob'][n - 1][1]\r\n\r\n        if (len(self.last_lob['asks']['lob']) < n):\r\n            a_n_1 = 0\r\n            q_n_1 = 0\r\n        else:\r\n            a_n_1 = self.last_lob['asks']['lob'][n - 1][0]\r\n            q_n_1 = self.last_lob['asks']['lob'][n - 1][1]\r\n\r\n        delta_w = 0;\r\n\r\n        if (b_n > b_n_1):\r\n            delta_w = r_n\r\n        elif (b_n == b_n_1):\r\n            delta_w = r_n - r_n_1\r\n        else:\r\n            delta_w = -r_n_1\r\n\r\n        delta_v = 0\r\n        if (a_n > a_n_1):\r\n            delta_v = -q_n_1\r\n        elif (a_n == a_n_1):\r\n            delta_v = q_n - q_n_1\r\n        else:\r\n            delta_v = q_n\r\n\r\n        return delta_w - delta_v\r\n\r\n    def calc_es(self, lob, m, verbose):\r\n        new_e = {}\r\n        for i in range(1, m + 1):\r\n            new_e['level' + str(i)] = self.calc_level_n_e(lob, i)\r\n\r\n        self.es_list.append(new_e)\r\n\r\n    def calc_ds(self, lob, m, verbose):\r\n        new_d = {}\r\n\r\n        for i in range(1, m + 1):\r\n            new_d['level' + str(i)] = self.cal_depth_n(lob, i)\r\n\r\n        self.ds_list.append(new_d)\r\n\r\n    def cal_depth_n(self, lob, n):\r\n\r\n        if (len(lob['bids']['lob']) < n):\r\n            r_n = 0\r\n        else:\r\n            r_n = lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(lob['asks']['lob']) < n):\r\n            q_n = 0\r\n        else:\r\n            q_n = lob['asks']['lob'][n - 1][1]\r\n        return (r_n + q_n) / 2\r\n\r\n    def calcEq(self):  ##clear and correct\r\n        # Slightly modified from paper, it is unclear inpaper\r\n        # N previous transactions * weights / N in vytelingum, swap N denominator for sum of weights to be correct?\r\n        if len(self.previous_transactions) == 0:\r\n            return\r\n        elif len(self.previous_transactions) < self.moving_average_window_size:\r\n            # Not enough transactions\r\n            self.estimated_equilibrium.append(\r\n                float(sum(self.previous_transactions)) / max(len(self.previous_transactions), 1))\r\n        else:\r\n            N_previous_transactions = self.previous_transactions[-self.moving_average_window_size:]\r\n            thing = [N_previous_transactions[i] * self.moving_average_weights[i] for i in\r\n                     range(self.moving_average_window_size)]\r\n            eq = sum(thing) / sum(self.moving_average_weights)\r\n            self.estimated_equilibrium.append(eq)\r\n\r\n    def calcAlpha(self):  ##correct. but calcAlpha in snashall's version is incorrect\r\n        alpha = 0.0\r\n        for p in self.previous_transactions:\r\n            alpha += (p - self.estimated_equilibrium[-1]) ** 2\r\n        alpha = math.sqrt(alpha / len(self.previous_transactions))\r\n        self.smiths_alpha.append(alpha / self.estimated_equilibrium[-1])\r\n\r\n    def calcTheta(self):  ## clear and correct\r\n        gamma = 2.0  # not sensitive apparently so choose to be whatever\r\n        # necessary for intialisation, div by 0\r\n        if min(self.smiths_alpha) == max(self.smiths_alpha):\r\n            alpha_range = 0.4  # starting value i guess\r\n        else:\r\n            alpha_range = (self.smiths_alpha[-1] - min(self.smiths_alpha)) / (\r\n                    max(self.smiths_alpha) - min(self.smiths_alpha))\r\n        theta_range = self.theta_max - self.theta_min\r\n        desired_theta = self.theta_min + (theta_range) * (1 - alpha_range) * math.exp(gamma * (alpha_range - 1))\r\n        self.theta = self.theta + self.long_term_learning_rate * (desired_theta - self.theta)\r\n        if self.theta > self.theta_max:\r\n            self.theta = self.theta_max\r\n        if self.theta < self.theta_min:\r\n            self.theta = self.theta_min\r\n\r\n    def calcRshout(self):  ## unclear in Vytelingum's paper\r\n        p = self.estimated_equilibrium[-1]\r\n        l = self.limit\r\n        theta = self.theta\r\n        if self.job == 'Bid':\r\n            # Currently a buyer\r\n            if l <= p:  # extramarginal!\r\n                self.r_shout = 0.0\r\n            else:  # intramarginal :(\r\n                if self.buy_target > self.estimated_equilibrium[-1]:\r\n                    # r[0,1]\r\n                    self.r_shout = math.log(((self.buy_target - p) * (math.exp(theta) - 1) / (l - p)) + 1) / theta\r\n                else:\r\n                    # r[-1,0]\r\n                    # print 'buy_target: %f , p: %f , theta: %f' %(self.buy_target,p,theta)\r\n                    self.r_shout = math.log((1 - (self.buy_target / p)) * (math.exp(theta) - 1) + 1) / theta\r\n                # self.r_shout = self.buy_r\r\n\r\n        if self.job == 'Ask':\r\n            # Currently a seller\r\n            if l >= p:  # extramarginal!\r\n                self.r_shout = 0\r\n            else:  # intramarginal :(\r\n                if self.sell_target > self.estimated_equilibrium[-1]:\r\n                    # r[-1,0]\r\n                    self.r_shout = math.log(\r\n                        (self.sell_target - p) * (math.exp(theta) - 1) / (self.marketMax - p) + 1) / theta\r\n                else:\r\n                    # r[0,1]\r\n                    a = (self.sell_target - l) / (p - l)\r\n                    self.r_shout = (math.log((1 - a) * (math.exp(theta) - 1) + 1)) / theta\r\n                # self.r_shout = self.sell_r\r\n\r\n    def calcAgg(self):\r\n        delta = 0\r\n        if self.job == 'Bid':\r\n            # BUYER\r\n            if self.buy_target >= self.previous_transactions[-1]:\r\n                # must be more aggressive\r\n                delta = (1 + self.r_shout_change_relative) * self.r_shout + self.r_shout_change_absolute\r\n            else:\r\n                delta = (1 - self.r_shout_change_relative) * self.r_shout - self.r_shout_change_absolute\r\n\r\n            self.buy_r = self.buy_r + self.short_term_learning_rate * (delta - self.buy_r)\r\n\r\n        if self.job == 'Ask':\r\n            # SELLER\r\n            if self.sell_target > self.previous_transactions[-1]:\r\n                delta = (1 + self.r_shout_change_relative) * self.r_shout + self.r_shout_change_absolute\r\n            else:\r\n                delta = (1 - self.r_shout_change_relative) * self.r_shout - self.r_shout_change_absolute\r\n\r\n            self.sell_r = self.sell_r + self.short_term_learning_rate * (delta - self.sell_r)\r\n\r\n    def calcTarget(self):\r\n        if len(self.estimated_equilibrium) > 0:\r\n            p = self.estimated_equilibrium[-1]\r\n            if self.limit == p:\r\n                p = p * 1.000001  # to prevent theta_bar = 0\r\n        elif self.job == 'Bid':\r\n            p = self.limit - self.limit * 0.2  ## Initial guess for eq if no deals yet!!....\r\n        elif self.job == 'Ask':\r\n            p = self.limit + self.limit * 0.2\r\n        l = self.limit\r\n        theta = self.theta\r\n        if self.job == 'Bid':\r\n            # BUYER\r\n            minus_thing = self.buy_r * math.exp(theta * (self.buy_r - 1))\r\n\r\n            if l <= p:  # Extramarginal\r\n                if self.buy_r >= 0:\r\n                    self.buy_target = l\r\n                else:\r\n                    self.buy_target = l * (1 - minus_thing)\r\n            else:  # intramarginal\r\n                if self.buy_r >= 0:\r\n                    # theta_ba = (p * math.exp(-theta))/(l-p)-1\r\n                    theta_ba = theta\r\n                    # print 'theta: %f' %(self.theta)\r\n                    # print 'theta_ba: %f '%(theta_ba)\r\n                    # print 'l-p: %f '%(l-p)\r\n                    # print 'self.buy_r :%f' %(self.buy_r)\r\n\r\n                    self.buy_target = (l - p) * (1 - (self.buy_r + 1) * math.exp(self.buy_r * theta_ba)) + p\r\n                else:\r\n                    self.buy_target = p * (1 - minus_thing)\r\n            if self.buy_target > l:\r\n                self.buy_target = l\r\n            if self.buy_target < bse_sys_minprice:\r\n                self.buy_target = bse_sys_minprice\r\n            # print 'buy_target = %f'%(self.buy_target)\r\n\r\n        if self.job == 'Ask':\r\n            # SELLER\r\n\r\n            if l <= p:  # Intramarginal\r\n                if self.buy_r >= 0:\r\n                    self.buy_target = p + (p - l) * self.sell_r * math.exp((self.sell_r - 1) * theta)\r\n                else:\r\n                    theta_ba = math.log((self.marketMax - p) / (p - l)) - theta\r\n                    self.buy_target = p + (self.marketMax - p) * self.sell_r * math.exp((self.sell_r + 1) * theta_ba)\r\n            else:  # Extramarginal\r\n                if self.buy_r >= 0:\r\n                    self.buy_target = l\r\n                else:\r\n                    self.buy_target = l + (self.marketMax - l) * self.sell_r * math.exp((self.sell_r - 1) * theta)\r\n            if self.sell_target < l:\r\n                self.sell_target = l\r\n            if self.sell_target > bse_sys_maxprice:\r\n                self.sell_target = bse_sys_maxprice\r\n            # print 'sell_target = %f'%(self.sell_target)\r\n\r\n    def getorder(self, time, countdown, lob, verbose):\r\n        if len(self.orders) < 1:\r\n            self.active = False\r\n            return None\r\n        else:\r\n            self.active = True\r\n            self.limit = self.orders[0].price\r\n            self.job = self.orders[0].atype\r\n            self.calcTarget()\r\n\r\n            if self.prev_best_bid_p == None:\r\n                o_bid = 0\r\n            else:\r\n                o_bid = self.prev_best_bid_p\r\n            if self.prev_best_ask_p == None:\r\n                o_ask = self.marketMax\r\n            else:\r\n                o_ask = self.prev_best_ask_p\r\n\r\n            if self.job == 'Bid':  # BUYER\r\n                if self.limit <= o_bid:\r\n                    return None\r\n                else:\r\n                    if len(self.previous_transactions) <= 0:  ## has been at least one transaction\r\n                        o_ask_plus = (1 + self.r_shout_change_relative) * o_ask + self.r_shout_change_absolute\r\n                        quoteprice = o_bid + ((min(self.limit, o_ask_plus) - o_bid) / self.offer_change_rate)\r\n                    else:\r\n                        if o_ask <= self.buy_target:\r\n                            quoteprice = o_ask\r\n                        else:\r\n                            quoteprice = o_bid + ((self.buy_target - o_bid) / self.offer_change_rate)\r\n            if self.job == 'Ask':\r\n                if self.limit >= o_ask:\r\n                    return None\r\n                else:\r\n                    if len(self.previous_transactions) <= 0:  ## has been at least one transaction\r\n                        o_bid_minus = (1 - self.r_shout_change_relative) * o_bid - self.r_shout_change_absolute\r\n                        quoteprice = o_ask - ((o_ask - max(self.limit, o_bid_minus)) / self.offer_change_rate)\r\n                    else:\r\n                        if o_bid >= self.sell_target:\r\n                            quoteprice = o_bid\r\n                        else:\r\n                            quoteprice = o_ask - ((o_ask - self.sell_target) / self.offer_change_rate)\r\n\r\n            def imbalance_alter(quoteprice_aa, lob, countdown, m):\r\n\r\n                mlofi_list = [0 for i in range(m)]\r\n                cd_list = [0 for i in range(m)]\r\n                ad_list = []\r\n                n = 1\r\n\r\n                while len(self.es_list) >= n:\r\n                    for i in range(m):\r\n                        mlofi_list[i] += self.es_list[-n]['level' + str(i+1)]\r\n                    n += 1\r\n                    if n >= 11:\r\n                        break\r\n\r\n                n = 1\r\n\r\n                while len(self.ds_list) >= n:\r\n                    for i in range(m):\r\n                        cd_list[i] += self.ds_list[-n]['level' + str(i+1)]\r\n                    n += 1\r\n                    if n >= 11:\r\n                        break\r\n\r\n                for i in range(m):\r\n                    temp = None\r\n                    if n == 1:\r\n                        temp = cd_list[i]+1\r\n                    else:\r\n                        temp = cd_list[i]/(n-1)+1\r\n                    ad_list.append(temp)\r\n\r\n                c = 5\r\n                decay = 0.8\r\n                offset = 0\r\n\r\n                for i in range(m):\r\n                    offset += int(mlofi_list[i]*c*pow(decay,i)/ ad_list[i])\r\n\r\n\r\n                benchmark = quoteprice_aa;\r\n                if(lob['midprice'] != None):\r\n                        benchmark = lob['midprice']\r\n                # print 'midprice is %d' % benchmark\r\n\r\n\r\n                quoteprice_iaa = quoteprice_aa + 0.8 * (benchmark + offset - quoteprice_aa)\r\n                if self.job == 'Bid' and quoteprice_iaa > self.limit:\r\n                    quoteprice_iaa = self.limit\r\n                if self.job == 'Ask' and quoteprice_iaa < self.limit:\r\n                    quoteprice_iaa = self.limit\r\n\r\n\r\n\r\n                if countdown < 0.3 :\r\n                    print \"insert\"\r\n                    if self.job == 'Bid' and (len(lob['asks']['lob']) >= 1) and lob['asks']['lob'][0][0] < self.limit:\r\n                        quoteprice_iaa = lob['asks']['lob'][0][0]\r\n                    if self.job == 'Ask' and (len(lob['bids']['lob']) >= 1) and lob['bids']['lob'][0][0] > self.limit:\r\n                        quoteprice_iaa = lob['bids']['lob'][0][0]\r\n\r\n                if self.job == 'Bid' and quoteprice_iaa < bse_sys_minprice:\r\n                    quoteprice_iaa = bse_sys_minprice + 1\r\n                if self.job == 'Ask' and quoteprice_iaa > bse_sys_maxprice:\r\n                    quoteprice_iaa = bse_sys_maxprice - 1\r\n\r\n                return quoteprice_iaa\r\n\r\n            quoteprice_iaa = imbalance_alter(quoteprice, lob, countdown,self.m)\r\n\r\n            order = Order(self.tid,\r\n                          self.orders[0].atype,\r\n                          'LIM',\r\n                          quoteprice_iaa,\r\n                          self.orders[0].qty,\r\n                          time, None, -1)\r\n            self.lastquote = order\r\n        return order\r\n\r\n    def respond(self, time, lob, trade, verbose):\r\n        ## Begin nicked from ZIP\r\n\r\n        # what, if anything, has happened on the bid LOB? Nicked from ZIP..\r\n        bid_improved = False\r\n        bid_hit = False\r\n        lob_best_bid_p = lob['bids']['bestp']\r\n        lob_best_bid_q = None\r\n        if lob_best_bid_p != None:\r\n            # non-empty bid LOB\r\n            lob_best_bid_q = lob['bids']['lob'][0][1]\r\n            if self.prev_best_bid_p < lob_best_bid_p:\r\n                # best bid has improved\r\n                # NB doesn't check if the improvement was by self\r\n                bid_improved = True\r\n            elif trade != None and ((self.prev_best_bid_p > lob_best_bid_p) or (\r\n                    (self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\r\n                # previous best bid was hit\r\n                bid_hit = True\r\n        elif self.prev_best_bid_p != None:\r\n            # # the bid LOB has been emptied: was it cancelled or hit?\r\n            # last_tape_item = lob['tape'][-1]\r\n            # if last_tape_item['type'] == 'Cancel' :\r\n            #         bid_hit = False\r\n            # else:\r\n            #         bid_hit = True\r\n            # the bid LOB is empty now but was not previously: so was it canceled or lifted?\r\n            if trade != None:\r\n                # a trade has occurred and the previously nonempty ask LOB is now empty\r\n                # so assume best ask was lifted\r\n                bid_hit = True\r\n            else:\r\n                bid_hit = False\r\n        # what, if anything, has happened on the ask LOB?\r\n        ask_improved = False\r\n        ask_lifted = False\r\n        lob_best_ask_p = lob['asks']['bestp']\r\n        lob_best_ask_q = None\r\n        if lob_best_ask_p != None:\r\n            # non-empty ask LOB\r\n            lob_best_ask_q = lob['asks']['lob'][0][1]\r\n            if self.prev_best_ask_p > lob_best_ask_p:\r\n                # best ask has improved -- NB doesn't check if the improvement was by self\r\n                ask_improved = True\r\n            elif trade != None and ((self.prev_best_ask_p < lob_best_ask_p) or (\r\n                    (self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\r\n                # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\r\n                ask_lifted = True\r\n        elif self.prev_best_ask_p != None:\r\n            # the ask LOB is empty now but was not previously: canceled or lifted?\r\n            # last_tape_item = lob['tape'][-1]\r\n            # if last_tape_item['type'] == 'Cancel' :\r\n            #         ask_lifted = False\r\n            # else:\r\n            #         ask_lifted = True\r\n            # the ask LOB is empty now but was not previously: so was it canceled or lifted?\r\n            if trade != None:\r\n                # a trade has occurred and the previously nonempty ask LOB is now empty\r\n                # so assume best ask was lifted\r\n                ask_lifted = True\r\n            else:\r\n                ask_lifted = False\r\n\r\n        self.prev_best_bid_p = lob_best_bid_p\r\n        self.prev_best_bid_q = lob_best_bid_q\r\n        self.prev_best_ask_p = lob_best_ask_p\r\n        self.prev_best_ask_q = lob_best_ask_q\r\n\r\n        deal = bid_hit or ask_lifted\r\n\r\n        ## End nicked from ZIP\r\n        if (self.last_lob == None):\r\n            self.last_lob = lob\r\n        else:\r\n            self.calc_es(lob, self.m, verbose)\r\n            self.calc_ds(lob, self.m, verbose)\r\n            self.last_lob = lob;\r\n\r\n        if deal:\r\n            self.previous_transactions.append(trade['price'])\r\n            if self.sell_target == None:\r\n                self.sell_target = trade['price']\r\n            if self.buy_target == None:\r\n                self.buy_target = trade['price']\r\n\r\n            self.calcEq()\r\n            self.calcAlpha()\r\n            self.calcTheta()\r\n            self.calcRshout()\r\n            self.calcAgg()\r\n            self.calcTarget()\r\n            # print 'sell: ', self.sell_target, 'buy: ', self.buy_target, 'limit:', self.limit, 'eq: ',  self.estimated_equilibrium[-1], 'sell_r: ', self.sell_r, 'buy_r: ', self.buy_r, '\\n'\r\n"
  },
  {
    "path": "ZhenZhang/source/IAA_NEW.py",
    "content": "\r\nfrom BSE2_msg_classes import Assignment, Order, Exch_msg\r\nfrom BSE_trader_agents import Trader;\r\nimport random\r\nimport math\r\n\r\nbse_sys_minprice = 1  # minimum price in the system, in cents/pennies\r\nbse_sys_maxprice = 200  # maximum price in the system, in cents/pennies\r\n\r\n\r\nclass Trader_IAA_NEW(Trader):\r\n\r\n    def __init__(self, ttype, tid, balance, time,m):\r\n\r\n        Trader.__init__(self, ttype, tid, balance, time)\r\n\r\n        self.limit = None\r\n        self.job = None\r\n\r\n        # learning variables\r\n        self.r_shout_change_relative = 0.05\r\n        self.r_shout_change_absolute = 0.05\r\n        self.short_term_learning_rate = random.uniform(0.1, 0.5)\r\n        self.long_term_learning_rate = random.uniform(0.1, 0.5)\r\n        self.moving_average_weight_decay = 0.95  # how fast weight decays with time, lower is quicker, 0.9 in vytelingum\r\n        self.moving_average_window_size = 5\r\n        self.offer_change_rate = 3.0\r\n        self.theta = -2.0\r\n        self.theta_max = 2.0\r\n        self.theta_min = -8.0\r\n        self.marketMax = bse_sys_maxprice\r\n\r\n        # Variables to describe the market\r\n        self.previous_transactions = []\r\n        self.moving_average_weights = []\r\n        for i in range(self.moving_average_window_size):\r\n            self.moving_average_weights.append(self.moving_average_weight_decay ** i)\r\n        self.estimated_equilibrium = []\r\n        self.smiths_alpha = []\r\n        self.prev_best_bid_p = None\r\n        self.prev_best_bid_q = None\r\n        self.prev_best_ask_p = None\r\n        self.prev_best_ask_q = None\r\n\r\n        # Trading Variables\r\n        self.r_shout = None\r\n        self.buy_target = None\r\n        self.sell_target = None\r\n        self.buy_r = -1.0 * (0.3 * random.random())\r\n        self.sell_r = -1.0 * (0.3 * random.random())\r\n\r\n        # variable for MLOFI\r\n        self.last_lob = None;\r\n        self.es_list = [];\r\n        self.ds_list = [];\r\n\r\n        #variable for ratio\r\n        self.bids_volume_list = []\r\n        self.asks_volume_list = []\r\n\r\n        # m\r\n        self.m = m;\r\n\r\n\r\n    def is_imbalance_significant(self, m,threshold):\r\n        cb_list = [0 for i in range(m)]\r\n        ab_list = []\r\n\r\n        ca_list = [0 for i in range(m)]\r\n        aa_list = []\r\n\r\n        n = 1\r\n\r\n        while len(self.bids_volume_list) >= n and len(self.asks_volume_list) >= n:\r\n            for i in range(m):\r\n                cb_list[i] += self.bids_volume_list[-n]['level' + str(i + 1)]\r\n                ca_list[i] += self.asks_volume_list[-n]['level' + str(i + 1)]\r\n            n += 1\r\n            if n >= 11:\r\n                break\r\n\r\n\r\n        for i in range(m):\r\n            temp1 = None\r\n            temp2 = None\r\n            if n == 1:\r\n                temp1 = cb_list[i] + 1\r\n                temp2 = ca_list[i] + 1\r\n            else:\r\n                temp1 = cb_list[i] / (n - 1) + 1\r\n                temp2 = ca_list[i] / (n - 1) + 1\r\n            ab_list.append(temp1)\r\n            aa_list.append(temp2)\r\n\r\n        v_bid = 0;\r\n        v_ask = 0;\r\n        for i in range(m):\r\n            v_bid += math.exp(-0.5*i)*ab_list[i];\r\n            v_ask += math.exp(-0.5*i)*aa_list[i];\r\n        ratio = (v_bid-v_ask)/(v_bid+v_ask);\r\n\r\n        # print self.bids_volume_list\r\n        # print self.asks_volume_list\r\n        # print ratio\r\n\r\n        if(ratio>threshold or ratio<-threshold):\r\n            return True\r\n        else:\r\n            return False\r\n\r\n\r\n\r\n\r\n\r\n    def calc_bids_volume(self, lob, m, verbose):\r\n        new_b = {}\r\n\r\n        for i in range(1, m + 1):\r\n            new_b['level' + str(i)] = self.cal_bids_n(lob, i)\r\n\r\n        self.bids_volume_list.append(new_b)\r\n\r\n    def cal_bids_n(self, lob, n):\r\n\r\n        if (len(lob['bids']['lob']) < n):\r\n            r_n = 0\r\n        else:\r\n            r_n = lob['bids']['lob'][n - 1][1]\r\n\r\n        return r_n\r\n\r\n    def calc_asks_volume(self, lob, m, verbose):\r\n        new_a = {}\r\n\r\n        for i in range(1, m + 1):\r\n            new_a['level' + str(i)] = self.cal_asks_n(lob, i);\r\n\r\n        self.asks_volume_list.append(new_a)\r\n\r\n    def cal_asks_n(self, lob, n):\r\n\r\n        if (len(lob['asks']['lob']) < n):\r\n            q_n = 0\r\n        else:\r\n            q_n = lob['asks']['lob'][n - 1][1]\r\n        return q_n\r\n\r\n    def calc_level_n_e(self, current_lob, n):\r\n        b_n = 0\r\n        r_n = 0\r\n        a_n = 0\r\n        q_n = 0\r\n\r\n        b_n_1 = 0\r\n        r_n_1 = 0\r\n        a_n_1 = 0\r\n        q_n_1 = 0\r\n\r\n        if (len(current_lob['bids']['lob']) < n):\r\n            b_n = 0\r\n            r_n = 0\r\n        else:\r\n            b_n = current_lob['bids']['lob'][n - 1][0]\r\n            r_n = current_lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(self.last_lob['bids']['lob']) < n):\r\n            b_n_1 = 0\r\n            r_n_1 = 0\r\n        else:\r\n            b_n_1 = self.last_lob['bids']['lob'][n - 1][0]\r\n            r_n_1 = self.last_lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(current_lob['asks']['lob']) < n):\r\n            a_n = 0\r\n            q_n = 0\r\n        else:\r\n            a_n = current_lob['asks']['lob'][n - 1][0]\r\n            q_n = current_lob['asks']['lob'][n - 1][1]\r\n\r\n        if (len(self.last_lob['asks']['lob']) < n):\r\n            a_n_1 = 0\r\n            q_n_1 = 0\r\n        else:\r\n            a_n_1 = self.last_lob['asks']['lob'][n - 1][0]\r\n            q_n_1 = self.last_lob['asks']['lob'][n - 1][1]\r\n\r\n        delta_w = 0;\r\n\r\n        if (b_n > b_n_1):\r\n            delta_w = r_n\r\n        elif (b_n == b_n_1):\r\n            delta_w = r_n - r_n_1\r\n        else:\r\n            delta_w = -r_n_1\r\n\r\n        delta_v = 0\r\n        if (a_n > a_n_1):\r\n            delta_v = -q_n_1\r\n        elif (a_n == a_n_1):\r\n            delta_v = q_n - q_n_1\r\n        else:\r\n            delta_v = q_n\r\n\r\n        return delta_w - delta_v\r\n\r\n    def calc_es(self, lob, m, verbose):\r\n        new_e = {}\r\n        for i in range(1, m + 1):\r\n            new_e['level' + str(i)] = self.calc_level_n_e(lob, i)\r\n\r\n        self.es_list.append(new_e)\r\n\r\n    def calc_ds(self, lob, m, verbose):\r\n        new_d = {}\r\n\r\n        for i in range(1, m + 1):\r\n            new_d['level' + str(i)] = self.cal_depth_n(lob, i)\r\n\r\n        self.ds_list.append(new_d)\r\n\r\n    def cal_depth_n(self, lob, n):\r\n\r\n        if (len(lob['bids']['lob']) < n):\r\n            r_n = 0\r\n        else:\r\n            r_n = lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(lob['asks']['lob']) < n):\r\n            q_n = 0\r\n        else:\r\n            q_n = lob['asks']['lob'][n - 1][1]\r\n        return (r_n + q_n) / 2\r\n\r\n    def calcEq(self):  ##clear and correct\r\n        # Slightly modified from paper, it is unclear inpaper\r\n        # N previous transactions * weights / N in vytelingum, swap N denominator for sum of weights to be correct?\r\n        if len(self.previous_transactions) == 0:\r\n            return\r\n        elif len(self.previous_transactions) < self.moving_average_window_size:\r\n            # Not enough transactions\r\n            self.estimated_equilibrium.append(\r\n                float(sum(self.previous_transactions)) / max(len(self.previous_transactions), 1))\r\n        else:\r\n            N_previous_transactions = self.previous_transactions[-self.moving_average_window_size:]\r\n            thing = [N_previous_transactions[i] * self.moving_average_weights[i] for i in\r\n                     range(self.moving_average_window_size)]\r\n            eq = sum(thing) / sum(self.moving_average_weights)\r\n            self.estimated_equilibrium.append(eq)\r\n\r\n    def calcAlpha(self):  ##correct. but calcAlpha in snashall's version is incorrect\r\n        alpha = 0.0\r\n        for p in self.previous_transactions:\r\n            alpha += (p - self.estimated_equilibrium[-1]) ** 2\r\n        alpha = math.sqrt(alpha / len(self.previous_transactions))\r\n        self.smiths_alpha.append(alpha / self.estimated_equilibrium[-1])\r\n\r\n    def calcTheta(self):  ## clear and correct\r\n        gamma = 2.0  # not sensitive apparently so choose to be whatever\r\n        # necessary for intialisation, div by 0\r\n        if min(self.smiths_alpha) == max(self.smiths_alpha):\r\n            alpha_range = 0.4  # starting value i guess\r\n        else:\r\n            alpha_range = (self.smiths_alpha[-1] - min(self.smiths_alpha)) / (\r\n                    max(self.smiths_alpha) - min(self.smiths_alpha))\r\n        theta_range = self.theta_max - self.theta_min\r\n        desired_theta = self.theta_min + (theta_range) * (1 - alpha_range) * math.exp(gamma * (alpha_range - 1))\r\n        self.theta = self.theta + self.long_term_learning_rate * (desired_theta - self.theta)\r\n        if self.theta > self.theta_max:\r\n            self.theta = self.theta_max\r\n        if self.theta < self.theta_min:\r\n            self.theta = self.theta_min\r\n\r\n    def calcRshout(self):  ## unclear in Vytelingum's paper\r\n        p = self.estimated_equilibrium[-1]\r\n        l = self.limit\r\n        theta = self.theta\r\n        if self.job == 'Bid':\r\n            # Currently a buyer\r\n            if l <= p:  # extramarginal!\r\n                self.r_shout = 0.0\r\n            else:  # intramarginal :(\r\n                if self.buy_target > self.estimated_equilibrium[-1]:\r\n                    # r[0,1]\r\n                    self.r_shout = math.log(((self.buy_target - p) * (math.exp(theta) - 1) / (l - p)) + 1) / theta\r\n                else:\r\n                    # r[-1,0]\r\n                    # print 'buy_target: %f , p: %f , theta: %f' %(self.buy_target,p,theta)\r\n                    self.r_shout = math.log((1 - (self.buy_target / p)) * (math.exp(theta) - 1) + 1) / theta\r\n                # self.r_shout = self.buy_r\r\n\r\n        if self.job == 'Ask':\r\n            # Currently a seller\r\n            if l >= p:  # extramarginal!\r\n                self.r_shout = 0\r\n            else:  # intramarginal :(\r\n                if self.sell_target > self.estimated_equilibrium[-1]:\r\n                    # r[-1,0]\r\n                    self.r_shout = math.log(\r\n                        (self.sell_target - p) * (math.exp(theta) - 1) / (self.marketMax - p) + 1) / theta\r\n                else:\r\n                    # r[0,1]\r\n                    a = (self.sell_target - l) / (p - l)\r\n                    self.r_shout = (math.log((1 - a) * (math.exp(theta) - 1) + 1)) / theta\r\n                # self.r_shout = self.sell_r\r\n\r\n    def calcAgg(self):\r\n        delta = 0\r\n        if self.job == 'Bid':\r\n            # BUYER\r\n            if self.buy_target >= self.previous_transactions[-1]:\r\n                # must be more aggressive\r\n                delta = (1 + self.r_shout_change_relative) * self.r_shout + self.r_shout_change_absolute\r\n            else:\r\n                delta = (1 - self.r_shout_change_relative) * self.r_shout - self.r_shout_change_absolute\r\n\r\n            self.buy_r = self.buy_r + self.short_term_learning_rate * (delta - self.buy_r)\r\n\r\n        if self.job == 'Ask':\r\n            # SELLER\r\n            if self.sell_target > self.previous_transactions[-1]:\r\n                delta = (1 + self.r_shout_change_relative) * self.r_shout + self.r_shout_change_absolute\r\n            else:\r\n                delta = (1 - self.r_shout_change_relative) * self.r_shout - self.r_shout_change_absolute\r\n\r\n            self.sell_r = self.sell_r + self.short_term_learning_rate * (delta - self.sell_r)\r\n\r\n    def calcTarget(self):\r\n        if len(self.estimated_equilibrium) > 0:\r\n            p = self.estimated_equilibrium[-1]\r\n            if self.limit == p:\r\n                p = p * 1.000001  # to prevent theta_bar = 0\r\n        elif self.job == 'Bid':\r\n            p = self.limit - self.limit * 0.2  ## Initial guess for eq if no deals yet!!....\r\n        elif self.job == 'Ask':\r\n            p = self.limit + self.limit * 0.2\r\n        l = self.limit\r\n        theta = self.theta\r\n        if self.job == 'Bid':\r\n            # BUYER\r\n            minus_thing = self.buy_r * math.exp(theta * (self.buy_r - 1))\r\n\r\n            if l <= p:  # Extramarginal\r\n                if self.buy_r >= 0:\r\n                    self.buy_target = l\r\n                else:\r\n                    self.buy_target = l * (1 - minus_thing)\r\n            else:  # intramarginal\r\n                if self.buy_r >= 0:\r\n                    # theta_ba = (p * math.exp(-theta))/(l-p)-1\r\n                    theta_ba = theta\r\n                    # print 'theta: %f' %(self.theta)\r\n                    # print 'theta_ba: %f '%(theta_ba)\r\n                    # print 'l-p: %f '%(l-p)\r\n                    # print 'self.buy_r :%f' %(self.buy_r)\r\n\r\n                    self.buy_target = (l - p) * (1 - (self.buy_r + 1) * math.exp(self.buy_r * theta_ba)) + p\r\n                else:\r\n                    self.buy_target = p * (1 - minus_thing)\r\n            if self.buy_target > l:\r\n                self.buy_target = l\r\n            if self.buy_target < bse_sys_minprice:\r\n                self.buy_target = bse_sys_minprice\r\n            # print 'buy_target = %f'%(self.buy_target)\r\n\r\n        if self.job == 'Ask':\r\n            # SELLER\r\n\r\n            if l <= p:  # Intramarginal\r\n                if self.buy_r >= 0:\r\n                    self.buy_target = p + (p - l) * self.sell_r * math.exp((self.sell_r - 1) * theta)\r\n                else:\r\n                    theta_ba = math.log((self.marketMax - p) / (p - l)) - theta\r\n                    self.buy_target = p + (self.marketMax - p) * self.sell_r * math.exp((self.sell_r + 1) * theta_ba)\r\n            else:  # Extramarginal\r\n                if self.buy_r >= 0:\r\n                    self.buy_target = l\r\n                else:\r\n                    self.buy_target = l + (self.marketMax - l) * self.sell_r * math.exp((self.sell_r - 1) * theta)\r\n            if self.sell_target < l:\r\n                self.sell_target = l\r\n            if self.sell_target > bse_sys_maxprice:\r\n                self.sell_target = bse_sys_maxprice\r\n            # print 'sell_target = %f'%(self.sell_target)\r\n\r\n    def getorder(self, time, countdown, lob, verbose):\r\n        if len(self.orders) < 1:\r\n            self.active = False\r\n            return None\r\n        else:\r\n            self.active = True\r\n            self.limit = self.orders[0].price\r\n            self.job = self.orders[0].atype\r\n            self.calcTarget()\r\n\r\n            if self.prev_best_bid_p == None:\r\n                o_bid = 0\r\n            else:\r\n                o_bid = self.prev_best_bid_p\r\n            if self.prev_best_ask_p == None:\r\n                o_ask = self.marketMax\r\n            else:\r\n                o_ask = self.prev_best_ask_p\r\n\r\n            if self.job == 'Bid':  # BUYER\r\n                if self.limit <= o_bid:\r\n                    return None\r\n                else:\r\n                    if len(self.previous_transactions) <= 0:  ## has been at least one transaction\r\n                        o_ask_plus = (1 + self.r_shout_change_relative) * o_ask + self.r_shout_change_absolute\r\n                        quoteprice = o_bid + ((min(self.limit, o_ask_plus) - o_bid) / self.offer_change_rate)\r\n                    else:\r\n                        if o_ask <= self.buy_target:\r\n                            quoteprice = o_ask\r\n                        else:\r\n                            quoteprice = o_bid + ((self.buy_target - o_bid) / self.offer_change_rate)\r\n            if self.job == 'Ask':\r\n                if self.limit >= o_ask:\r\n                    return None\r\n                else:\r\n                    if len(self.previous_transactions) <= 0:  ## has been at least one transaction\r\n                        o_bid_minus = (1 - self.r_shout_change_relative) * o_bid - self.r_shout_change_absolute\r\n                        quoteprice = o_ask - ((o_ask - max(self.limit, o_bid_minus)) / self.offer_change_rate)\r\n                    else:\r\n                        if o_bid >= self.sell_target:\r\n                            quoteprice = o_bid\r\n                        else:\r\n                            quoteprice = o_ask - ((o_ask - self.sell_target) / self.offer_change_rate)\r\n\r\n            def imbalance_alter(quoteprice_aa, lob, countdown, m):\r\n\r\n                mlofi_list = [0 for i in range(m)]\r\n                cd_list = [0 for i in range(m)]\r\n                ad_list = []\r\n                n = 1\r\n\r\n                while len(self.es_list) >= n:\r\n                    for i in range(m):\r\n                        mlofi_list[i] += self.es_list[-n]['level' + str(i+1)]\r\n                    n += 1\r\n                    if n >= 11:\r\n                        break\r\n\r\n                n = 1\r\n\r\n                while len(self.ds_list) >= n:\r\n                    for i in range(m):\r\n                        cd_list[i] += self.ds_list[-n]['level' + str(i+1)]\r\n                    n += 1\r\n                    if n >= 11:\r\n                        break\r\n\r\n                for i in range(m):\r\n                    temp = None\r\n                    if n == 1:\r\n                        temp = cd_list[i]+1\r\n                    else:\r\n                        temp = cd_list[i]/(n-1)+1\r\n                    ad_list.append(temp)\r\n\r\n                c = 5\r\n                decay = 0.8\r\n                offset = 0\r\n\r\n                for i in range(m):\r\n                    offset += int(mlofi_list[i]*c*pow(decay,i)/ ad_list[i])\r\n\r\n\r\n                benchmark = quoteprice_aa;\r\n                if(lob['midprice'] != None):\r\n                        benchmark = lob['midprice']\r\n                # print 'midprice is %d' % benchmark\r\n\r\n                quoteprice_iaa = quoteprice_aa + 0.8 * (benchmark + offset - quoteprice_aa)\r\n                if self.job == 'Bid' and quoteprice_iaa > self.limit:\r\n                    quoteprice_iaa = self.limit\r\n                if self.job == 'Ask' and quoteprice_iaa < self.limit:\r\n                    quoteprice_iaa = self.limit\r\n\r\n                if countdown < 0.3 :\r\n                    print \"insert\"\r\n                    if self.job == 'Bid' and (len(lob['asks']['lob']) >= 1) and lob['asks']['lob'][0][0] < self.limit:\r\n                        quoteprice_iaa = lob['asks']['lob'][0][0]\r\n                    if self.job == 'Ask' and (len(lob['bids']['lob']) >= 1) and lob['bids']['lob'][0][0] > self.limit:\r\n                        quoteprice_iaa = lob['bids']['lob'][0][0]\r\n\r\n                return quoteprice_iaa\r\n\r\n            if(self.is_imbalance_significant(self.m,0.6)):\r\n                # print \"abvious\"\r\n                quoteprice_iaa = imbalance_alter(quoteprice, lob, countdown, self.m)\r\n            else:\r\n                # print \"not abvious\"\r\n                quoteprice_iaa = quoteprice\r\n\r\n\r\n            order = Order(self.tid,\r\n                          self.orders[0].atype,\r\n                          'LIM',\r\n                          quoteprice_iaa,\r\n                          self.orders[0].qty,\r\n                          time, None, -1)\r\n            self.lastquote = order\r\n        return order\r\n\r\n    def respond(self, time, lob, trade, verbose):\r\n        ## Begin nicked from ZIP\r\n\r\n        # what, if anything, has happened on the bid LOB? Nicked from ZIP..\r\n        bid_improved = False\r\n        bid_hit = False\r\n        lob_best_bid_p = lob['bids']['bestp']\r\n        lob_best_bid_q = None\r\n        if lob_best_bid_p != None:\r\n            # non-empty bid LOB\r\n            lob_best_bid_q = lob['bids']['lob'][0][1]\r\n            if self.prev_best_bid_p < lob_best_bid_p:\r\n                # best bid has improved\r\n                # NB doesn't check if the improvement was by self\r\n                bid_improved = True\r\n            elif trade != None and ((self.prev_best_bid_p > lob_best_bid_p) or (\r\n                    (self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\r\n                # previous best bid was hit\r\n                bid_hit = True\r\n        elif self.prev_best_bid_p != None:\r\n            # # the bid LOB has been emptied: was it cancelled or hit?\r\n            # last_tape_item = lob['tape'][-1]\r\n            # if last_tape_item['type'] == 'Cancel' :\r\n            #         bid_hit = False\r\n            # else:\r\n            #         bid_hit = True\r\n            # the bid LOB is empty now but was not previously: so was it canceled or lifted?\r\n            if trade != None:\r\n                # a trade has occurred and the previously nonempty ask LOB is now empty\r\n                # so assume best ask was lifted\r\n                bid_hit = True\r\n            else:\r\n                bid_hit = False\r\n        # what, if anything, has happened on the ask LOB?\r\n        ask_improved = False\r\n        ask_lifted = False\r\n        lob_best_ask_p = lob['asks']['bestp']\r\n        lob_best_ask_q = None\r\n        if lob_best_ask_p != None:\r\n            # non-empty ask LOB\r\n            lob_best_ask_q = lob['asks']['lob'][0][1]\r\n            if self.prev_best_ask_p > lob_best_ask_p:\r\n                # best ask has improved -- NB doesn't check if the improvement was by self\r\n                ask_improved = True\r\n            elif trade != None and ((self.prev_best_ask_p < lob_best_ask_p) or (\r\n                    (self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\r\n                # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\r\n                ask_lifted = True\r\n        elif self.prev_best_ask_p != None:\r\n            # the ask LOB is empty now but was not previously: canceled or lifted?\r\n            # last_tape_item = lob['tape'][-1]\r\n            # if last_tape_item['type'] == 'Cancel' :\r\n            #         ask_lifted = False\r\n            # else:\r\n            #         ask_lifted = True\r\n            # the ask LOB is empty now but was not previously: so was it canceled or lifted?\r\n            if trade != None:\r\n                # a trade has occurred and the previously nonempty ask LOB is now empty\r\n                # so assume best ask was lifted\r\n                ask_lifted = True\r\n            else:\r\n                ask_lifted = False\r\n\r\n        self.prev_best_bid_p = lob_best_bid_p\r\n        self.prev_best_bid_q = lob_best_bid_q\r\n        self.prev_best_ask_p = lob_best_ask_p\r\n        self.prev_best_ask_q = lob_best_ask_q\r\n\r\n        deal = bid_hit or ask_lifted\r\n\r\n        ## End nicked from ZIP\r\n        if (self.last_lob == None):\r\n            self.last_lob = lob\r\n        else:\r\n            self.calc_es(lob, self.m, verbose)\r\n            self.calc_ds(lob, self.m, verbose)\r\n            self.calc_bids_volume(lob, self.m, verbose)\r\n            self.calc_asks_volume(lob, self.m, verbose)\r\n            self.last_lob = lob;\r\n\r\n        if deal:\r\n            self.previous_transactions.append(trade['price'])\r\n            if self.sell_target == None:\r\n                self.sell_target = trade['price']\r\n            if self.buy_target == None:\r\n                self.buy_target = trade['price']\r\n\r\n            self.calcEq()\r\n            self.calcAlpha()\r\n            self.calcTheta()\r\n            self.calcRshout()\r\n            self.calcAgg()\r\n            self.calcTarget()\r\n            # print 'sell: ', self.sell_target, 'buy: ', self.buy_target, 'limit:', self.limit, 'eq: ',  self.estimated_equilibrium[-1], 'sell_r: ', self.sell_r, 'buy_r: ', self.buy_r, '\\n'\r\n"
  },
  {
    "path": "ZhenZhang/source/IGDX_MLOFI.py",
    "content": "# Trader subclass ZIP\r\n# After Cliff 1997\r\n\r\n\r\nfrom BSE2_msg_classes import Assignment, Order, Exch_msg\r\nfrom BSE_trader_agents import Trader;\r\nimport random\r\nimport math\r\n\r\nbse_sys_minprice = 1  # minimum price in the system, in cents/pennies\r\nbse_sys_maxprice = 200  # maximum price in the system, in cents/pennies\r\n\r\nclass Trader_IGDX_MLOFI(Trader):\r\n\r\n        def __init__(self, ttype, tid, balance, time,m):\r\n                Trader.__init__(self, ttype, tid, balance, time)\r\n                self.active = False\r\n                self.limit = None\r\n                self.job = None\r\n\r\n                #memory of all bids and asks and accepted bids and asks\r\n                self.outstanding_bids = []\r\n                self.outstanding_asks = []\r\n                self.accepted_asks = []\r\n                self.accepted_bids = []\r\n\r\n                self.price = -1\r\n\r\n                # memory of best price & quantity of best bid and ask, on LOB on previous update\r\n                self.prev_best_bid_p = None\r\n                self.prev_best_bid_q = None\r\n                self.prev_best_ask_p = None\r\n                self.prev_best_ask_q = None\r\n\r\n                self.first_turn = True\r\n\r\n                self.gamma = 0.1\r\n\r\n                self.holdings = 10\r\n                self.remaining_offer_ops = 10\r\n                self.values = [[0 for n in range(self.remaining_offer_ops)] for m in range(self.holdings)]\r\n\r\n                # variable for MLOFI\r\n                self.last_lob = None;\r\n                self.es_list = [];\r\n                self.ds_list = [];\r\n\r\n                # variable for ratio\r\n                self.bids_volume_list = []\r\n                self.asks_volume_list = []\r\n\r\n                # variable\r\n                self.m = m;\r\n\r\n        def is_imbalance_significant(self, m, threshold):\r\n            cb_list = [0 for i in range(m)]\r\n            ab_list = []\r\n\r\n            ca_list = [0 for i in range(m)]\r\n            aa_list = []\r\n\r\n            n = 1\r\n\r\n            while len(self.bids_volume_list) >= n and len(self.asks_volume_list) >= n:\r\n                for i in range(m):\r\n                    cb_list[i] += self.bids_volume_list[-n]['level' + str(i + 1)]\r\n                    ca_list[i] += self.asks_volume_list[-n]['level' + str(i + 1)]\r\n                n += 1\r\n                if n >= 11:\r\n                    break\r\n\r\n            for i in range(m):\r\n                temp1 = None\r\n                temp2 = None\r\n                if n == 1:\r\n                    temp1 = cb_list[i] + 1\r\n                    temp2 = ca_list[i] + 1\r\n                else:\r\n                    temp1 = cb_list[i] / (n - 1) + 1\r\n                    temp2 = ca_list[i] / (n - 1) + 1\r\n                ab_list.append(temp1)\r\n                aa_list.append(temp2)\r\n\r\n            v_bid = 0;\r\n            v_ask = 0;\r\n            for i in range(m):\r\n                v_bid += math.exp(-0.5 * i) * ab_list[i];\r\n                v_ask += math.exp(-0.5 * i) * aa_list[i];\r\n            ratio = (v_bid - v_ask) / (v_bid + v_ask);\r\n\r\n            # print self.bids_volume_list\r\n            # print self.asks_volume_list\r\n            # print ratio\r\n\r\n            if (ratio > threshold or ratio < -threshold):\r\n                return True\r\n            else:\r\n                return False\r\n\r\n        def calc_bids_volume(self, lob, m, verbose):\r\n            new_b = {}\r\n\r\n            for i in range(1, m + 1):\r\n                new_b['level' + str(i)] = self.cal_bids_n(lob, i)\r\n\r\n            self.bids_volume_list.append(new_b)\r\n\r\n        def cal_bids_n(self, lob, n):\r\n\r\n            if (len(lob['bids']['lob']) < n):\r\n                r_n = 0\r\n            else:\r\n                r_n = lob['bids']['lob'][n - 1][1]\r\n\r\n            return r_n\r\n\r\n        def calc_asks_volume(self, lob, m, verbose):\r\n            new_a = {}\r\n\r\n            for i in range(1, m + 1):\r\n                new_a['level' + str(i)] = self.cal_asks_n(lob, i);\r\n\r\n            self.asks_volume_list.append(new_a)\r\n\r\n        def cal_asks_n(self, lob, n):\r\n\r\n            if (len(lob['asks']['lob']) < n):\r\n                q_n = 0\r\n            else:\r\n                q_n = lob['asks']['lob'][n - 1][1]\r\n            return q_n\r\n\r\n        def calc_level_n_e(self, current_lob, n):\r\n            b_n = 0\r\n            r_n = 0\r\n            a_n = 0\r\n            q_n = 0\r\n\r\n            b_n_1 = 0\r\n            r_n_1 = 0\r\n            a_n_1 = 0\r\n            q_n_1 = 0\r\n\r\n            if (len(current_lob['bids']['lob']) < n):\r\n                b_n = 0\r\n                r_n = 0\r\n            else:\r\n                b_n = current_lob['bids']['lob'][n - 1][0]\r\n                r_n = current_lob['bids']['lob'][n - 1][1]\r\n\r\n            if (len(self.last_lob['bids']['lob']) < n):\r\n                b_n_1 = 0\r\n                r_n_1 = 0\r\n            else:\r\n                b_n_1 = self.last_lob['bids']['lob'][n - 1][0]\r\n                r_n_1 = self.last_lob['bids']['lob'][n - 1][1]\r\n\r\n            if (len(current_lob['asks']['lob']) < n):\r\n                a_n = 0\r\n                q_n = 0\r\n            else:\r\n                a_n = current_lob['asks']['lob'][n - 1][0]\r\n                q_n = current_lob['asks']['lob'][n - 1][1]\r\n\r\n            if (len(self.last_lob['asks']['lob']) < n):\r\n                a_n_1 = 0\r\n                q_n_1 = 0\r\n            else:\r\n                a_n_1 = self.last_lob['asks']['lob'][n - 1][0]\r\n                q_n_1 = self.last_lob['asks']['lob'][n - 1][1]\r\n\r\n            delta_w = 0;\r\n\r\n            if (b_n > b_n_1):\r\n                delta_w = r_n\r\n            elif (b_n == b_n_1):\r\n                delta_w = r_n - r_n_1\r\n            else:\r\n                delta_w = -r_n_1\r\n\r\n            delta_v = 0\r\n            if (a_n > a_n_1):\r\n                delta_v = -q_n_1\r\n            elif (a_n == a_n_1):\r\n                delta_v = q_n - q_n_1\r\n            else:\r\n                delta_v = q_n\r\n\r\n            return delta_w - delta_v\r\n\r\n        def calc_es(self, lob, m, verbose):\r\n            new_e = {}\r\n            for i in range(1, m + 1):\r\n                new_e['level' + str(i)] = self.calc_level_n_e(lob, i)\r\n\r\n            self.es_list.append(new_e)\r\n\r\n        def calc_ds(self, lob, m, verbose):\r\n            new_d = {}\r\n\r\n            for i in range(1, m + 1):\r\n                new_d['level' + str(i)] = self.cal_depth_n(lob, i)\r\n\r\n            self.ds_list.append(new_d)\r\n\r\n        def cal_depth_n(self, lob, n):\r\n\r\n            if (len(lob['bids']['lob']) < n):\r\n                r_n = 0\r\n            else:\r\n                r_n = lob['bids']['lob'][n - 1][1]\r\n\r\n            if (len(lob['asks']['lob']) < n):\r\n                q_n = 0\r\n            else:\r\n                q_n = lob['asks']['lob'][n - 1][1]\r\n            return (r_n + q_n) / 2\r\n\r\n\r\n        def getorder(self, time, countdown, lob, verbose):\r\n                def imbalance_alter(quoteprice_aa, lob, countdown, m):\r\n\r\n                    mlofi_list = [0 for i in range(m)]\r\n                    cd_list = [0 for i in range(m)]\r\n                    ad_list = []\r\n                    n = 1\r\n\r\n                    while len(self.es_list) >= n:\r\n                        for i in range(m):\r\n                            mlofi_list[i] += self.es_list[-n]['level' + str(i + 1)]\r\n                        n += 1\r\n                        if n >= 11:\r\n                            break\r\n\r\n                    n = 1\r\n\r\n                    while len(self.ds_list) >= n:\r\n                        for i in range(m):\r\n                            cd_list[i] += self.ds_list[-n]['level' + str(i + 1)]\r\n                        n += 1\r\n                        if n >= 11:\r\n                            break\r\n\r\n                    for i in range(m):\r\n                        temp = None\r\n                        if n == 1:\r\n                            temp = cd_list[i] + 1\r\n                        else:\r\n                            temp = cd_list[i] / (n - 1) + 1\r\n                        ad_list.append(temp)\r\n\r\n                    c = 5\r\n                    decay = 0.8\r\n                    offset = 0\r\n\r\n                    for i in range(m):\r\n                        offset += int(mlofi_list[i] * c * pow(decay, i) / ad_list[i])\r\n\r\n                    benchmark = quoteprice_aa;\r\n                    if (lob['midprice'] != None):\r\n                        benchmark = lob['midprice']\r\n                    # print 'midprice is %d' % benchmark\r\n\r\n                    quoteprice_iaa = quoteprice_aa + 0.8 * (benchmark + offset - quoteprice_aa)\r\n\r\n                    if self.job == 'Bid' and quoteprice_iaa > self.limit:\r\n                        quoteprice_iaa = self.limit\r\n                    if self.job == 'Ask' and quoteprice_iaa < self.limit:\r\n                        quoteprice_iaa = self.limit\r\n\r\n\r\n\r\n                    if countdown < 0.3:\r\n                        print \"insert\"\r\n                        if self.job == 'Bid' and (len(lob['asks']['lob']) >= 1) and lob['asks']['lob'][0][0] < self.limit:\r\n                            quoteprice_iaa = lob['asks']['lob'][0][0]\r\n                        if self.job == 'Ask' and (len(lob['bids']['lob']) >= 1) and lob['bids']['lob'][0][0] > self.limit:\r\n                            quoteprice_iaa = lob['bids']['lob'][0][0]\r\n\r\n                    if self.job == 'Bid' and quoteprice_iaa < bse_sys_minprice:\r\n                        quoteprice_iaa = bse_sys_minprice+1\r\n                    if self.job == 'Ask' and quoteprice_iaa > bse_sys_maxprice:\r\n                        quoteprice_iaa = bse_sys_maxprice-1\r\n\r\n\r\n                    return quoteprice_iaa\r\n\r\n\r\n\r\n                if len(self.orders) < 1:\r\n                        self.active = False\r\n                        order = None\r\n                        return order\r\n                else:\r\n                        self.active = True\r\n                        self.limit = self.orders[0].price\r\n                        self.job = self.orders[0].atype\r\n\r\n                        #calculate price\r\n                        if self.job == 'Bid':\r\n                                self.price = self.calc_p_bid(self.holdings - 1, self.remaining_offer_ops - 1)\r\n                        if self.job == 'Ask':\r\n                                self.price = self.calc_p_ask(self.holdings - 1, self.remaining_offer_ops - 1)\r\n\r\n                        quoteprice = self.price\r\n\r\n                        # print \"before:\"\r\n                        # print self.price\r\n                        if (self.is_imbalance_significant(self.m, 0.6)):\r\n                            # print \"abvious\"\r\n                            quoteprice_igdx = imbalance_alter(quoteprice, lob, countdown, self.m)\r\n                        else:\r\n                            # print \"not abvious\"\r\n                            quoteprice_igdx = quoteprice\r\n\r\n\r\n\r\n\r\n                        self.price = quoteprice_igdx\r\n                        #\r\n                        # print \"after:\"\r\n                        # print self.price\r\n                        order = Order(self.tid, self.job, 'LIM',self.price, self.orders[0].qty, time, None,  -1)\r\n                        self.lastquote = order\r\n\r\n                if self.first_turn or self.price == -1:\r\n                    if self.job == 'Bid':\r\n                        order = Order(self.tid, self.job, 'LIM', bse_sys_minprice+1, self.orders[0].qty, time, None, -1)\r\n                    if self.job == 'Ask':\r\n                        order = Order(self.tid, self.job, 'LIM', bse_sys_maxprice-1, self.orders[0].qty, time, None, -1)\r\n                        # print order\r\n\r\n                return order\r\n\r\n        def calc_p_bid(self, m, n):\r\n                best_return = 0\r\n                best_bid = 0\r\n                second_best_return = 0\r\n                second_best_bid = 0\r\n\r\n                #first step size of 1 get best and 2nd best\r\n                for i in [x*2 for x in range(int(self.limit/2))]:\r\n                        thing = self.belief_buy(i) * ((self.limit - i) + self.gamma*self.values[m-1][n-1]) + (1-self.belief_buy(i) * self.gamma * self.values[m][n-1])\r\n                        if thing > best_return:\r\n                                second_best_bid = best_bid\r\n                                second_best_return = best_return\r\n                                best_return = thing\r\n                                best_bid = i\r\n\r\n                #always best bid largest one\r\n                if second_best_bid > best_bid:\r\n                        a = second_best_bid\r\n                        second_best_bid = best_bid\r\n                        best_bid = a\r\n\r\n                #then step size 0.05\r\n                for i in [x*0.05 for x in range(int(second_best_bid), int(best_bid))]:\r\n                        thing = self.belief_buy(i + second_best_bid) * ((self.limit - (i + second_best_bid)) + self.gamma*self.values[m-1][n-1]) + (1-self.belief_buy(i + second_best_bid) * self.gamma * self.values[m][n-1])\r\n                        if thing > best_return:\r\n                                best_return = thing\r\n                                best_bid = i + second_best_bid\r\n\r\n                return best_bid\r\n\r\n        def calc_p_ask(self, m, n):\r\n                best_return = 0\r\n                best_ask = self.limit\r\n                second_best_return = 0\r\n                second_best_ask = self.limit\r\n\r\n                #first step size of 1 get best and 2nd best\r\n                for i in [x*2 for x in range(int(self.limit/2))]:\r\n                        j = i + self.limit\r\n                        thing =  self.belief_sell(j) * ((j - self.limit) + self.gamma*self.values[m-1][n-1]) + (1-self.belief_sell(j) * self.gamma * self.values[m][n-1])\r\n                        if thing > best_return:\r\n                                second_best_ask = best_ask\r\n                                second_best_return = best_return\r\n                                best_return = thing\r\n                                best_ask = j\r\n                #always best ask largest one\r\n                if second_best_ask > best_ask:\r\n                        a = second_best_ask\r\n                        second_best_ask = best_ask\r\n                        best_ask = a\r\n\r\n                #then step size 0.05\r\n                for i in [x*0.05 for x in range(int(second_best_ask), int(best_ask))]:\r\n                        thing = self.belief_sell(i + second_best_ask) * (((i + second_best_ask) - self.limit) + self.gamma*self.values[m-1][n-1]) + (1-self.belief_sell(i + second_best_ask) * self.gamma * self.values[m][n-1])\r\n                        if thing > best_return:\r\n                                best_return = thing\r\n                                best_ask = i + second_best_ask\r\n\r\n                return best_ask\r\n\r\n        def belief_sell(self, price):\r\n                accepted_asks_greater = 0\r\n                bids_greater = 0\r\n                unaccepted_asks_lower = 0\r\n                for p in self.accepted_asks:\r\n                        if p >= price:\r\n                                accepted_asks_greater += 1\r\n                for p in [thing[0] for thing in self.outstanding_bids]:\r\n                        if p >= price:\r\n                                bids_greater += 1\r\n                for p in [thing[0] for thing in self.outstanding_asks]:\r\n                        if p <= price:\r\n                                unaccepted_asks_lower += 1\r\n\r\n                if accepted_asks_greater + bids_greater + unaccepted_asks_lower == 0:\r\n                        return 0\r\n                return (accepted_asks_greater + bids_greater) / (accepted_asks_greater + bids_greater + unaccepted_asks_lower)\r\n\r\n        def belief_buy(self, price):\r\n                accepted_bids_lower = 0\r\n                asks_lower = 0\r\n                unaccepted_bids_greater = 0\r\n                for p in self.accepted_bids:\r\n                        if p <= price:\r\n                                accepted_bids_lower += 1\r\n                for p in [thing[0] for thing in self.outstanding_asks]:\r\n                        if p <= price:\r\n                                asks_lower += 1\r\n                for p in [thing[0] for thing in self.outstanding_bids]:\r\n                        if p >= price:\r\n                                unaccepted_bids_greater += 1\r\n                if accepted_bids_lower + asks_lower + unaccepted_bids_greater == 0:\r\n                        return 0\r\n                return (accepted_bids_lower + asks_lower) / (accepted_bids_lower + asks_lower + unaccepted_bids_greater)\r\n\r\n        def respond(self, time, lob, trade, verbose):\r\n\r\n                if (self.last_lob == None):\r\n                    self.last_lob = lob\r\n                else:\r\n                    self.calc_es(lob, self.m, verbose)\r\n                    self.calc_ds(lob, self.m, verbose)\r\n                    self.calc_bids_volume(lob, self.m, verbose)\r\n                    self.calc_asks_volume(lob, self.m, verbose)\r\n                    self.last_lob = lob;\r\n\r\n                # what, if anything, has happened on the bid LOB?\r\n                self.outstanding_bids = lob['bids']['lob']\r\n                bid_improved = False\r\n                bid_hit = False\r\n                lob_best_bid_p = lob['bids']['bestp']\r\n                lob_best_bid_q = None\r\n                if lob_best_bid_p != None:\r\n                        # non-empty bid LOB\r\n                        lob_best_bid_q = lob['bids']['lob'][-1][1]\r\n                        if self.prev_best_bid_p < lob_best_bid_p :\r\n                                # best bid has improved\r\n                                # NB doesn't check if the improvement was by self\r\n                                bid_improved = True\r\n                        elif trade != None and ((self.prev_best_bid_p > lob_best_bid_p) or ((self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\r\n                                # previous best bid was hit\r\n                                self.accepted_bids.append(self.prev_best_bid_p)\r\n                                bid_hit = True\r\n                elif self.prev_best_bid_p != None:\r\n                        # the bid LOB has been emptied: was it cancelled or hit?\r\n                        last_tape_item = lob['tape'][-1]\r\n                        if last_tape_item['type'] == 'Cancel' :\r\n                                bid_hit = False\r\n                        else:\r\n                                bid_hit = True\r\n\r\n                # what, if anything, has happened on the ask LOB?\r\n                self.outstanding_asks = lob['asks']['lob']\r\n                ask_improved = False\r\n                ask_lifted = False\r\n                lob_best_ask_p = lob['asks']['bestp']\r\n                lob_best_ask_q = None\r\n                if lob_best_ask_p != None:\r\n                        # non-empty ask LOB\r\n                        lob_best_ask_q = lob['asks']['lob'][0][1]\r\n                        if self.prev_best_ask_p > lob_best_ask_p :\r\n                                # best ask has improved -- NB doesn't check if the improvement was by self\r\n                                ask_improved = True\r\n                        elif trade != None and ((self.prev_best_ask_p < lob_best_ask_p) or ((self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\r\n                                # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\r\n                                self.accepted_asks.append(self.prev_best_ask_p)\r\n                                ask_lifted = True\r\n                elif self.prev_best_ask_p != None:\r\n                        # the ask LOB is empty now but was not previously: canceled or lifted?\r\n                        last_tape_item = lob['tape'][-1]\r\n                        if last_tape_item['type'] == 'Cancel' :\r\n                                ask_lifted = False\r\n                        else:\r\n                                ask_lifted = True\r\n\r\n\r\n                #populate expected values\r\n                if self.first_turn:\r\n                        # print \"populating\"\r\n                        self.first_turn = False\r\n                        for n in range(1, self.remaining_offer_ops):\r\n                                for m in range(1, self.holdings):\r\n                                            if self.job == 'Bid':\r\n                                                    #BUYER\r\n                                                    self.values[m][n] = self.calc_p_bid(m, n)\r\n\r\n                                            if self.job == 'Ask':\r\n                                                    #BUYER\r\n                                                    self.values[m][n] = self.calc_p_ask(m, n)\r\n                        # print \"done\"\r\n\r\n\r\n                deal = bid_hit or ask_lifted\r\n\r\n\r\n                # remember the best LOB data ready for next response\r\n                self.prev_best_bid_p = lob_best_bid_p\r\n                self.prev_best_bid_q = lob_best_bid_q\r\n                self.prev_best_ask_p = lob_best_ask_p\r\n                self.prev_best_ask_q = lob_best_ask_q\r\n\r\n"
  },
  {
    "path": "ZhenZhang/source/IZIP_MLOFI.py",
    "content": "\r\nfrom BSE2_msg_classes import Assignment, Order, Exch_msg\r\nfrom BSE_trader_agents import Trader;\r\nimport random\r\nimport math\r\n\r\nbse_sys_minprice = 1  # minimum price in the system, in cents/pennies\r\nbse_sys_maxprice = 200  # maximum price in the system, in cents/pennies\r\n\r\nclass Trader_IZIP_MLOFI(Trader):\r\n\r\n    # ZIP init key param-values are those used in Cliff's 1997 original HP Labs tech report\r\n    # NB this implementation keeps separate margin values for buying & selling,\r\n    #    so a single trader can both buy AND sell\r\n    #    -- in the original, traders were either buyers OR sellers\r\n\r\n    def __init__(self, ttype, tid, balance, time, m):\r\n        Trader.__init__(self, ttype, tid, balance, time)\r\n        m_fix = 0.05\r\n        m_var = 0.05\r\n        self.job = None  # this is 'Bid' or 'Ask' depending on customer order\r\n        self.active = False  # gets switched to True while actively working an order\r\n        self.prev_change = 0  # this was called last_d in Cliff'97\r\n        self.beta = 0.1 + 0.2 * random.random()  # learning rate\r\n        self.momntm = 0.3 * random.random()  # momentum\r\n        self.ca = 0.10  # self.ca & .cr were hard-coded in '97 but parameterised later\r\n        self.cr = 0.10\r\n        self.margin = None  # this was called profit in Cliff'97\r\n        self.margin_buy = -1.0 * (m_fix + m_var * random.random())\r\n        self.margin_sell = m_fix + m_var * random.random()\r\n        self.price = None\r\n        self.limit = None\r\n        # memory of best price & quantity of best bid and ask, on LOB on previous update\r\n        self.prev_best_bid_p = None\r\n        self.prev_best_bid_q = None\r\n        self.prev_best_ask_p = None\r\n        self.prev_best_ask_q = None\r\n        # memory of worst prices from customer orders received so far\r\n        self.worst_bidprice = None\r\n        self.worst_askprice = None\r\n\r\n\r\n        # variable for MLOFI\r\n        self.last_lob = None;\r\n        self.es_list = [];\r\n        self.ds_list = [];\r\n\r\n        #variable for ratio\r\n        self.bids_volume_list = []\r\n        self.asks_volume_list = []\r\n\r\n        #variable\r\n        self.m = m;\r\n\r\n    def is_imbalance_significant(self, m,threshold):\r\n        cb_list = [0 for i in range(m)]\r\n        ab_list = []\r\n\r\n        ca_list = [0 for i in range(m)]\r\n        aa_list = []\r\n\r\n        n = 1\r\n\r\n        while len(self.bids_volume_list) >= n and len(self.asks_volume_list) >= n:\r\n            for i in range(m):\r\n                cb_list[i] += self.bids_volume_list[-n]['level' + str(i + 1)]\r\n                ca_list[i] += self.asks_volume_list[-n]['level' + str(i + 1)]\r\n            n += 1\r\n            if n >= 11:\r\n                break\r\n\r\n\r\n        for i in range(m):\r\n            temp1 = None\r\n            temp2 = None\r\n            if n == 1:\r\n                temp1 = cb_list[i] + 1\r\n                temp2 = ca_list[i] + 1\r\n            else:\r\n                temp1 = cb_list[i] / (n - 1) + 1\r\n                temp2 = ca_list[i] / (n - 1) + 1\r\n            ab_list.append(temp1)\r\n            aa_list.append(temp2)\r\n\r\n        v_bid = 0;\r\n        v_ask = 0;\r\n        for i in range(m):\r\n            v_bid += math.exp(-0.5*i)*ab_list[i];\r\n            v_ask += math.exp(-0.5*i)*aa_list[i];\r\n        ratio = (v_bid-v_ask)/(v_bid+v_ask);\r\n\r\n        # print self.bids_volume_list\r\n        # print self.asks_volume_list\r\n        # print ratio\r\n\r\n        if(ratio>threshold or ratio<-threshold):\r\n            return True\r\n        else:\r\n            return False\r\n\r\n\r\n\r\n\r\n\r\n    def calc_bids_volume(self, lob, m, verbose):\r\n        new_b = {}\r\n\r\n        for i in range(1, m + 1):\r\n            new_b['level' + str(i)] = self.cal_bids_n(lob, i)\r\n\r\n        self.bids_volume_list.append(new_b)\r\n\r\n    def cal_bids_n(self, lob, n):\r\n\r\n        if (len(lob['bids']['lob']) < n):\r\n            r_n = 0\r\n        else:\r\n            r_n = lob['bids']['lob'][n - 1][1]\r\n\r\n        return r_n\r\n\r\n    def calc_asks_volume(self, lob, m, verbose):\r\n        new_a = {}\r\n\r\n        for i in range(1, m + 1):\r\n            new_a['level' + str(i)] = self.cal_asks_n(lob, i);\r\n\r\n        self.asks_volume_list.append(new_a)\r\n\r\n    def cal_asks_n(self, lob, n):\r\n\r\n        if (len(lob['asks']['lob']) < n):\r\n            q_n = 0\r\n        else:\r\n            q_n = lob['asks']['lob'][n - 1][1]\r\n        return q_n\r\n\r\n    def calc_level_n_e(self, current_lob, n):\r\n        b_n = 0\r\n        r_n = 0\r\n        a_n = 0\r\n        q_n = 0\r\n\r\n        b_n_1 = 0\r\n        r_n_1 = 0\r\n        a_n_1 = 0\r\n        q_n_1 = 0\r\n\r\n        if (len(current_lob['bids']['lob']) < n):\r\n            b_n = 0\r\n            r_n = 0\r\n        else:\r\n            b_n = current_lob['bids']['lob'][n - 1][0]\r\n            r_n = current_lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(self.last_lob['bids']['lob']) < n):\r\n            b_n_1 = 0\r\n            r_n_1 = 0\r\n        else:\r\n            b_n_1 = self.last_lob['bids']['lob'][n - 1][0]\r\n            r_n_1 = self.last_lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(current_lob['asks']['lob']) < n):\r\n            a_n = 0\r\n            q_n = 0\r\n        else:\r\n            a_n = current_lob['asks']['lob'][n - 1][0]\r\n            q_n = current_lob['asks']['lob'][n - 1][1]\r\n\r\n        if (len(self.last_lob['asks']['lob']) < n):\r\n            a_n_1 = 0\r\n            q_n_1 = 0\r\n        else:\r\n            a_n_1 = self.last_lob['asks']['lob'][n - 1][0]\r\n            q_n_1 = self.last_lob['asks']['lob'][n - 1][1]\r\n\r\n        delta_w = 0;\r\n\r\n        if (b_n > b_n_1):\r\n            delta_w = r_n\r\n        elif (b_n == b_n_1):\r\n            delta_w = r_n - r_n_1\r\n        else:\r\n            delta_w = -r_n_1\r\n\r\n        delta_v = 0\r\n        if (a_n > a_n_1):\r\n            delta_v = -q_n_1\r\n        elif (a_n == a_n_1):\r\n            delta_v = q_n - q_n_1\r\n        else:\r\n            delta_v = q_n\r\n\r\n        return delta_w - delta_v\r\n\r\n    def calc_es(self, lob, m, verbose):\r\n        new_e = {}\r\n        for i in range(1, m + 1):\r\n            new_e['level' + str(i)] = self.calc_level_n_e(lob, i)\r\n\r\n        self.es_list.append(new_e)\r\n\r\n    def calc_ds(self, lob, m, verbose):\r\n        new_d = {}\r\n\r\n        for i in range(1, m + 1):\r\n            new_d['level' + str(i)] = self.cal_depth_n(lob, i)\r\n\r\n        self.ds_list.append(new_d)\r\n\r\n    def cal_depth_n(self, lob, n):\r\n\r\n        if (len(lob['bids']['lob']) < n):\r\n            r_n = 0\r\n        else:\r\n            r_n = lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(lob['asks']['lob']) < n):\r\n            q_n = 0\r\n        else:\r\n            q_n = lob['asks']['lob'][n - 1][1]\r\n        return (r_n + q_n) / 2\r\n\r\n\r\n\r\n    def __str__(self):\r\n        s = '%s, job=, %s, ' % (self.tid, self.job)\r\n        if self.active == True:\r\n            s = s + 'actv=,T, '\r\n        else:\r\n            s = s + 'actv=,F, '\r\n        if self.margin == None:\r\n            s = s + 'mrgn=,N,   '\r\n        else:\r\n            s = s + 'mrgn=,%5.2f, ' % self.margin\r\n        s = s + 'lmt=,%s, price=,%s, bestbid=,%s,@,%s, bestask=,%s,@,%s, wrstbid=,%s, wrstask=,%s' % \\\r\n            (self.limit, self.price, self.prev_best_bid_q, self.prev_best_bid_p, self.prev_best_ask_q,\r\n             self.prev_best_ask_p, self.worst_bidprice, self.worst_askprice)\r\n        return (s)\r\n\r\n    def getorder(self, time, countdown, lob, verbose):\r\n\r\n        if verbose: print('ZIP getorder(): LOB=%s' % lob)\r\n\r\n        # random coefficient, multiplier on trader's own estimate of worst possible bid/ask prices\r\n        # currently in arbitrarily chosen range [2, 5]\r\n        worst_coeff = 2 + (3 * random.random())\r\n\r\n        if len(self.orders) < 1:\r\n            self.active = False\r\n            order = None\r\n        else:\r\n            self.active = True\r\n            self.limit = self.orders[0].price\r\n            self.job = self.orders[0].atype\r\n            if self.job == 'Bid':\r\n                # currently a buyer (working a bid order)\r\n                self.margin = self.margin_buy\r\n                # what is the worst bid price on the LOB right now?\r\n                if len(lob['bids']['lob']) > 0:\r\n                    # take price of final entry on LOB\r\n                    worst_bid = lob['bids']['lob'][-1][0]\r\n                else:\r\n                    # local pessimistic estimate of the worst bid price (own version of stub quote)\r\n                    worst_bid = max(1, int(self.limit / worst_coeff))\r\n                if self.worst_bidprice == None:\r\n                    self.worst_bidprice = worst_bid\r\n                elif self.worst_bidprice > worst_bid:\r\n                    self.worst_bidprice = worst_bid\r\n            else:\r\n                # currently a seller (working a sell order)\r\n                self.margin = self.margin_sell\r\n                # what is the worst ask price on the LOB right now?\r\n                if len(lob['asks']['lob']) > 0:\r\n                    # take price of final entry on LOB\r\n                    worst_ask = lob['asks']['lob'][-1][0]\r\n                else:\r\n                    # local pessimistic estimate of the worst ask price (own version of stub quote)\r\n                    worst_ask = int(self.limit * worst_coeff)\r\n                if self.worst_askprice == None:\r\n                    self.worst_askprice = worst_ask\r\n                elif self.worst_askprice < worst_ask:\r\n                    self.worst_askprice = worst_ask\r\n\r\n            quoteprice = int(self.limit * (1 + self.margin))\r\n\r\n            def imbalance_alter(quoteprice_aa, lob, countdown, m):\r\n\r\n                mlofi_list = [0 for i in range(m)]\r\n                cd_list = [0 for i in range(m)]\r\n                ad_list = []\r\n                n = 1\r\n\r\n                while len(self.es_list) >= n:\r\n                    for i in range(m):\r\n                        mlofi_list[i] += self.es_list[-n]['level' + str(i+1)]\r\n                    n += 1\r\n                    if n >= 11:\r\n                        break\r\n\r\n                n = 1\r\n\r\n                while len(self.ds_list) >= n:\r\n                    for i in range(m):\r\n                        cd_list[i] += self.ds_list[-n]['level' + str(i+1)]\r\n                    n += 1\r\n                    if n >= 11:\r\n                        break\r\n\r\n                for i in range(m):\r\n                    temp = None\r\n                    if n == 1:\r\n                        temp = cd_list[i]+1\r\n                    else:\r\n                        temp = cd_list[i]/(n-1)+1\r\n                    ad_list.append(temp)\r\n\r\n                c = 10\r\n                decay = 1\r\n                offset = 0\r\n\r\n                for i in range(m):\r\n                    offset += int(mlofi_list[i]*c*pow(decay,i)/ ad_list[i])\r\n\r\n\r\n                benchmark = quoteprice_aa;\r\n                if(lob['midprice'] != None):\r\n                        benchmark = lob['midprice']\r\n                # print 'midprice is %d' % benchmark\r\n\r\n                quoteprice_iaa = quoteprice_aa + 0.8 * (benchmark + offset - quoteprice_aa)\r\n                if self.job == 'Bid' and quoteprice_iaa > self.limit:\r\n                    quoteprice_iaa = self.limit\r\n                if self.job == 'Ask' and quoteprice_iaa < self.limit:\r\n                    quoteprice_iaa = self.limit\r\n\r\n                if countdown < 0.3 :\r\n                    print \"insert\"\r\n                    if self.job == 'Bid' and (len(lob['asks']['lob']) >= 1) and lob['asks']['lob'][0][0] < self.limit:\r\n                        quoteprice_iaa = lob['asks']['lob'][0][0]+1\r\n                    if self.job == 'Ask' and (len(lob['bids']['lob']) >= 1) and lob['bids']['lob'][0][0] > self.limit:\r\n                        quoteprice_iaa = lob['bids']['lob'][0][0]-1\r\n\r\n\r\n                if self.job == 'Bid' and quoteprice_iaa < bse_sys_minprice:\r\n                    quoteprice_iaa = bse_sys_minprice + 1\r\n                if self.job == 'Ask' and quoteprice_iaa > bse_sys_maxprice:\r\n                    quoteprice_iaa = bse_sys_maxprice - 1\r\n\r\n                return quoteprice_iaa\r\n\r\n            # print \"before\"\r\n            # print quoteprice\r\n            # if(self.is_imbalance_significant(self.m,0.6)):\r\n            #     print \"abvious\"\r\n            #     quoteprice_izip = imbalance_alter(quoteprice, lob, countdown, self.m)\r\n            # else:\r\n            #     print \"not abvious\"\r\n            #     quoteprice_izip = quoteprice\r\n            quoteprice_izip = imbalance_alter(quoteprice, lob, countdown, self.m)\r\n            # print \"after\"\r\n            # print quoteprice_izip\r\n\r\n\r\n\r\n            self.price = quoteprice_izip\r\n\r\n            order = Order(self.tid, self.job, \"LIM\", quoteprice_izip, self.orders[0].qty, time, None, -1)\r\n            self.lastquote = order\r\n\r\n        return order\r\n\r\n    # update margin on basis of what happened in market\r\n    def respond(self, time, lob, trade, verbose):\r\n        # ZIP trader responds to market events, altering its margin\r\n        # does this whether it currently has an order to work or not\r\n\r\n\r\n        if (self.last_lob == None):\r\n            self.last_lob = lob\r\n        else:\r\n            self.calc_es(lob, self.m, verbose)\r\n            self.calc_ds(lob, self.m, verbose)\r\n            self.calc_bids_volume(lob, self.m, verbose)\r\n            self.calc_asks_volume(lob, self.m, verbose)\r\n            self.last_lob = lob;\r\n\r\n        def target_up(price):\r\n            # generate a higher target price by randomly perturbing given price\r\n            ptrb_abs = self.ca * random.random()  # absolute shift\r\n            ptrb_rel = price * (1.0 + (self.cr * random.random()))  # relative shift\r\n            target = int(round(ptrb_rel + ptrb_abs, 0))\r\n            if target == price: target = price + 1  # enforce minimal difference\r\n            # print('TargetUp: %d %d\\n' % (price, target))\r\n            return (target)\r\n\r\n        def target_down(price):\r\n            # generate a lower target price by randomly perturbing given price\r\n            ptrb_abs = self.ca * random.random()  # absolute shift\r\n            ptrb_rel = price * (1.0 - (self.cr * random.random()))  # relative shift\r\n            target = int(round(ptrb_rel - ptrb_abs, 0))\r\n            if target == price: target = price - 1  # enforce minimal difference\r\n            # print('TargetDn: %d %d\\n' % (price,target))\r\n            return (target)\r\n\r\n        def microshade(microprice, price):\r\n            # shade in the direction of the microprice\r\n            microweight = 0\r\n            if microprice != None:\r\n                shaded = ((microweight * microprice) + ((1 - microweight) * price))\r\n            else:\r\n                shaded = price\r\n            # print('Microshade: micro=%s price=%s shaded=%s' % (microprice, price, shaded))\r\n            return (shaded)\r\n\r\n        def willing_to_trade(price):\r\n            # am I willing to trade at this price?\r\n            willing = False\r\n            if self.job == 'Bid' and self.active and self.price >= price:\r\n                willing = True\r\n            if self.job == 'Ask' and self.active and self.price <= price:\r\n                willing = True\r\n            return willing\r\n\r\n        def profit_alter(*argv):\r\n            # this has variable number of parameters\r\n            # if passed a single numeric value, that's the target price\r\n            # if passed three numeric values, that's the price, beta (learning rate), and momentum\r\n            if len(argv) == 1:\r\n                price = argv[0]\r\n                beta = self.beta\r\n                momntm = self.momntm\r\n            elif len(argv) == 3:\r\n                price = argv[0]\r\n                beta = argv[1]\r\n                momntm = argv[2]\r\n            else:\r\n                sys.stdout.flush()\r\n                sys.exit('Fail: ZIP profit_alter given wrong number of parameters')\r\n\r\n            # print('profit_alter: price=%s beta=%s momntm=%s' % (price, beta, momntm))\r\n            oldprice = self.price\r\n            diff = price - oldprice\r\n            change = ((1.0 - self.momntm) * (self.beta * diff)) + (self.momntm * self.prev_change)\r\n            self.prev_change = change\r\n            newmargin = ((self.price + change) / self.limit) - 1.0\r\n\r\n            if self.job == 'Bid':\r\n                margin = min(newmargin, 0)\r\n                self.margin_buy = margin\r\n                self.margin = margin\r\n            else:\r\n                margin = max(0, newmargin)\r\n                self.margin_sell = margin\r\n                self.margin = margin\r\n\r\n            # set the price from limit and profit-margin\r\n            self.price = int(round(self.limit * (1.0 + self.margin), 0))\r\n            # print('old=%d diff=%d change=%d lim=%d price = %d\\n' % (oldprice, diff, change, self.limit, self.price))\r\n\r\n        if verbose and trade != None: print('respond() [ZIP] time=%s tid=%s, trade=%s LOB[bids]=%s LOB[asks]=%s' %\r\n                                            (time, self.tid, trade, lob[\"bids\"], lob[\"asks\"]))\r\n\r\n        # what, if anything, has happened on the bid LOB?\r\n\r\n        # if trade != None: print('ZIP respond() trade=%s' % trade)\r\n\r\n        bid_improved = False\r\n        bid_hit = False\r\n\r\n        if len(lob['bids']['lob']) > 0:\r\n            lob_best_bid_p = lob['bids']['lob'][0][0]\r\n        else:\r\n            lob_best_bid_p = None\r\n\r\n        lob_best_bid_q = None  # default assumption\r\n\r\n        if lob_best_bid_p != None:\r\n            # non-empty bid LOB\r\n\r\n            if self.prev_best_bid_p > lob_best_bid_p:\r\n                best_bid_p_decreased = True\r\n            else:\r\n                best_bid_p_decreased = False\r\n\r\n            if (self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q):\r\n                same_p_smaller_q = True\r\n            else:\r\n                same_p_smaller_q = False\r\n\r\n            lob_best_bid_q = lob['bids']['lob'][0][1]\r\n\r\n            if self.prev_best_bid_p < lob_best_bid_p:\r\n                # best bid has improved\r\n                # NB doesn't check if the improvement was by self\r\n                bid_improved = True\r\n            elif trade != None and (best_bid_p_decreased or same_p_smaller_q):\r\n                # there WAS a trade and either...\r\n                # ... (best bid price has gone DOWN) or (best bid price is same but quantity at that price has gone DOWN)\r\n                # then assume previous best bid was hit\r\n                bid_hit = True\r\n\r\n        elif self.prev_best_bid_p != None:\r\n            # the bid LOB is empty now but was not previously: so was it canceled or lifted?\r\n            if trade != None:\r\n                # a trade has occurred and the previously nonempty ask LOB is now empty\r\n                # so assume best ask was lifted\r\n                bid_hit = True\r\n            else:\r\n                bid_hit = False\r\n\r\n        if verbose: print(\"LOB[bids]=%s bid_improved=%s bid_hit=%s\" % (lob['bids'], bid_improved, bid_hit))\r\n\r\n        # what, if anything, has happened on the ask LOB?\r\n\r\n        ask_improved = False\r\n        ask_lifted = False\r\n\r\n        if len(lob['asks']['lob']) > 0:\r\n            lob_best_ask_p = lob['asks']['lob'][0][0]\r\n        else:\r\n            lob_best_ask_p = None\r\n\r\n        lob_best_ask_q = None\r\n\r\n        if lob_best_ask_p != None:\r\n            # non-empty ask LOB\r\n\r\n            if self.prev_best_ask_p < lob_best_ask_p:\r\n                best_ask_p_increased = True\r\n            else:\r\n                best_ask_p_increased = False\r\n\r\n            if (self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q):\r\n                same_p_smaller_q = True\r\n            else:\r\n                same_p_smaller_q = False\r\n\r\n            lob_best_ask_q = lob['asks']['lob'][0][1]\r\n            if self.prev_best_ask_p > lob_best_ask_p:\r\n                # best ask has improved -- NB doesn't check if the improvement was by self\r\n                ask_improved = True\r\n            elif trade != None and (best_ask_p_increased or same_p_smaller_q):\r\n                # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\r\n                ask_lifted = True\r\n\r\n        elif self.prev_best_ask_p != None:\r\n            # the ask LOB is empty now but was not previously: so was it canceled or lifted?\r\n            if trade != None:\r\n                # a trade has occurred and the previously nonempty ask LOB is now empty\r\n                # so assume best ask was lifted\r\n                ask_lifted = True\r\n            else:\r\n                ask_lifted = False\r\n\r\n        if verbose: print(\"LOB[asks]=%s ask_improved=%s ask_lifted=%s\" % (lob['asks'], ask_improved, ask_lifted))\r\n\r\n        if verbose and (bid_improved or bid_hit or ask_improved or ask_lifted):\r\n            print('ZIP respond() B_improved=%s; B_hit=%s A_improved=%s, A_lifted=%s' % (\r\n            bid_improved, bid_hit, ask_improved, ask_lifted))\r\n            print('Trade=%s\\n' % trade)\r\n\r\n        # we want to know: did a deal just happen?\r\n        # if not, did the most recent bid\r\n\r\n        deal = bid_hit or ask_lifted\r\n\r\n        # previously...\r\n        # when raising margin, tradeprice = trade['price'], targetprice = f(tradeprice) &\r\n        # i.e. target price will be calculated relative to price of most recent transaction\r\n        # and when lowering margin, targetprice = f(best_price_on_counterparty_side_of_LOB) or\r\n        # or if LOB empty then targetprice = f(worst possible counterparty quote) <-- a system constant\r\n\r\n        # new in this version:\r\n        # take account of LOB's microprice if it is defined (if not, use trade['price'] as before)\r\n\r\n        midp = lob['midprice']\r\n        microp = lob['microprice']\r\n\r\n        # KLUDGE for TESTING\r\n        if time > 79: microp = 145\r\n\r\n        if microp != None and midp != None:\r\n            imbalance = microp - midp\r\n        else:\r\n            imbalance = 0  # uses zero instead of None because a zero imbalance reverts ZIP to original form\r\n\r\n        target_price = None  # default assumption\r\n\r\n        # print('self.job=%s' % self.job)\r\n\r\n        if self.job == 'Ask':\r\n            # seller\r\n            if deal:\r\n                if verbose: print ('trade', trade)\r\n                tradeprice = trade['price']  # price of most recent transaction\r\n                # print('tradeprice=%s lob[microprice]=%s' % (tradeprice, lob['microprice']))\r\n                # shadetrade = microshade(lob['microprice'], tradeprice)\r\n                # refprice = shadetrade\r\n                refprice = tradeprice\r\n\r\n                if self.price <= tradeprice:\r\n                    # could sell for more? raise margin\r\n                    target_price = target_up(refprice)\r\n                    profit_alter(target_price)\r\n                elif ask_lifted and self.active and not willing_to_trade(tradeprice):\r\n                    # previous best ask was hit,\r\n                    # but this trader wouldn't have got the deal cos price to high,\r\n                    # and still working a customer order, so reduce margin\r\n                    target_price = target_down(refprice)\r\n                    profit_alter(target_price)\r\n            else:\r\n                # no deal: aim for a target price higher than best bid\r\n                # print('lob_best_bid_p=%s lob[microprice]=%s' % (lob_best_bid_p, lob['microprice']))\r\n                # refprice = microshade(lob['microprice'], lob_best_bid_p)\r\n                refprice = lob_best_bid_p\r\n\r\n                if ask_improved and self.price > lob_best_bid_p:\r\n                    if lob_best_bid_p != None:\r\n                        target_price = target_up(lob_best_bid_p)\r\n                    else:\r\n                        if self.worst_askprice != None:\r\n                            target_price = self.worst_askprice\r\n                            print('worst_askprice = %s' % self.worst_askprice)\r\n                            target_price = None  # todo: does this stop the price-spikes?\r\n                        else:\r\n                            target_price = None\r\n                        # target_price = lob['asks']['worstp']  # stub quote\r\n                    if target_price != None:\r\n                        print('PA1: tp=%s' % target_price)\r\n                        profit_alter(target_price)\r\n\r\n        if self.job == 'Bid':\r\n            # buyer\r\n            if deal:\r\n                tradeprice = trade['price']\r\n                # shadetrade = microshade(lob['microprice'], tradeprice)\r\n                # refprice = shadetrade\r\n                refprice = tradeprice\r\n\r\n                if lob['microprice'] != None and lob['midprice'] != None:\r\n                    delta = lob['microprice'] - lob['midprice']\r\n                    # refprice = refprice + delta\r\n\r\n                if self.price >= tradeprice:\r\n                    # could buy for less? raise margin (i.e. cut the price)\r\n                    target_price = target_down(refprice)\r\n                    profit_alter(target_price)\r\n                elif bid_hit and self.active and not willing_to_trade(tradeprice):\r\n                    # wouldn't have got this deal, and still working a customer order,\r\n                    # so reduce margin\r\n                    target_price = target_up(refprice)\r\n                    profit_alter(target_price)\r\n            else:\r\n                # no deal: aim for target price lower than best ask\r\n                refprice = microshade(lob['microprice'], lob_best_ask_p)\r\n                if bid_improved and self.price < lob_best_ask_p:\r\n                    if lob_best_ask_p != None:\r\n                        target_price = target_down(lob_best_ask_p)\r\n                    else:\r\n                        if self.worst_bidprice != None:\r\n                            target_price = self.worst_bidprice\r\n                            target_price = None\r\n                        else:\r\n                            target_price = None\r\n                        # target_price = lob['bids']['worstp']  # stub quote\r\n                    if target_price != None:\r\n                        # print('PA2: tp=%s' % target_price)\r\n                        profit_alter(target_price)\r\n\r\n        # print('time,%f,>>>,microprice,%s,>>>,target_price,%s' % (time, lob['microprice'], target_price))\r\n\r\n        # remember the best LOB data ready for next response\r\n        self.prev_best_bid_p = lob_best_bid_p\r\n        self.prev_best_bid_q = lob_best_bid_q\r\n        self.prev_best_ask_p = lob_best_ask_p\r\n        self.prev_best_ask_q = lob_best_ask_q\r\n\r\n##########################---trader-types have all been defined now--################"
  },
  {
    "path": "ZhenZhang/source/Simple_MLOFI.py",
    "content": "from BSE2_msg_classes import Assignment, Order, Exch_msg\r\nfrom BSE_trader_agents import Trader;\r\nimport random\r\nimport math\r\n\r\nbse_sys_minprice = 1  # minimum price in the system, in cents/pennies\r\nbse_sys_maxprice = 200  # maximum price in the system, in cents/pennies\r\n\r\nclass Trader_Simple_MLOFI(Trader):\r\n\r\n    def __init__(self, ttype, tid, balance, time):\r\n\r\n        Trader.__init__(self, ttype, tid, balance, time)\r\n\r\n        self.limit = None\r\n        self.job = None\r\n\r\n\r\n        # variable for MLOFI\r\n        self.last_lob = None;\r\n        self.list_OFI = [];\r\n        self.list_D = [];\r\n\r\n    def cal_level_n_e(self, current_lob, n):\r\n        b_n = 0\r\n        r_n = 0\r\n        a_n = 0\r\n        q_n = 0\r\n\r\n        b_n_1 = 0\r\n        r_n_1 = 0\r\n        a_n_1 = 0\r\n        q_n_1 = 0\r\n\r\n        if (len(current_lob['bids']['lob']) < n):\r\n            b_n = 0\r\n            r_n = 0\r\n        else:\r\n            b_n = current_lob['bids']['lob'][n - 1][0]\r\n            r_n = current_lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(self.last_lob['bids']['lob']) < n):\r\n            b_n_1 = 0\r\n            r_n_1 = 0\r\n        else:\r\n            b_n_1 = self.last_lob['bids']['lob'][n - 1][0]\r\n            r_n_1 = self.last_lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(current_lob['asks']['lob']) < n):\r\n            a_n = 0\r\n            q_n = 0\r\n        else:\r\n            a_n = current_lob['asks']['lob'][n - 1][0]\r\n            q_n = current_lob['asks']['lob'][n - 1][1]\r\n\r\n        if (len(self.last_lob['asks']['lob']) < n):\r\n            a_n_1 = 0\r\n            q_n_1 = 0\r\n        else:\r\n            a_n_1 = self.last_lob['asks']['lob'][n - 1][0]\r\n            q_n_1 = self.last_lob['asks']['lob'][n - 1][1]\r\n\r\n        delta_w = 0;\r\n\r\n        if (b_n > b_n_1):\r\n            delta_w = r_n\r\n        elif (b_n == b_n_1):\r\n            delta_w = r_n - r_n_1\r\n        else:\r\n            delta_w = -r_n_1\r\n\r\n        delta_v = 0\r\n        if (a_n > a_n_1):\r\n            delta_v = -q_n_1\r\n        elif (a_n == a_n_1):\r\n            delta_v = q_n - q_n_1\r\n        else:\r\n            delta_v = q_n\r\n\r\n        return delta_w - delta_v\r\n\r\n    def cal_e(self, time, lob, trade, verbose):\r\n\r\n        level_1 = self.cal_level_n_e(lob, 1)\r\n        level_2 = self.cal_level_n_e(lob, 2)\r\n        level_3 = self.cal_level_n_e(lob, 3)\r\n        e = {\r\n            'level1': level_1,\r\n            'level2': level_2,\r\n            'level3': level_3,\r\n        }\r\n        # print 'ofi is:'\r\n        # print str(e)\r\n        self.list_OFI.append(e)\r\n\r\n    def cal_depth(self, lob):\r\n        level_1 = self.cal_depth_n(lob, 1)\r\n        level_2 = self.cal_depth_n(lob, 2)\r\n        level_3 = self.cal_depth_n(lob, 3)\r\n        d = {\r\n            'level1': level_1,\r\n            'level2': level_2,\r\n            'level3': level_3,\r\n        }\r\n        # print 'depth is:'\r\n        # print str(d)\r\n        self.list_D.append(d);\r\n\r\n    def cal_depth_n(self, lob, n):\r\n\r\n        if (len(lob['bids']['lob']) < n):\r\n            r_n = 0\r\n        else:\r\n            r_n = lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(lob['asks']['lob']) < n):\r\n            q_n = 0\r\n        else:\r\n            q_n = lob['asks']['lob'][n - 1][1]\r\n        return (r_n + q_n) / 2\r\n\r\n\r\n    def getorder(self, time, countdown, lob, verbose):\r\n        if len(self.orders) < 1:\r\n            self.active = False\r\n            return None\r\n        else:\r\n            self.limit = self.orders[0].price\r\n            otype = self.orders[0].atype\r\n            self.job = self.orders[0].atype\r\n            ostyle = self.orders[0].astyle\r\n            if otype == 'Bid':\r\n                if lob['bids']['n'] > 0:\r\n                    quoteprice = lob['bids']['bestp']\r\n                    if quoteprice > self.limit:\r\n                        quoteprice = self.limit\r\n                else:\r\n                    quoteprice = self.limit\r\n            else:\r\n                if lob['asks']['n'] > 0:\r\n                    quoteprice = lob['asks']['bestp']\r\n                    if quoteprice < self.limit:\r\n                        quoteprice = self.limit\r\n                else:\r\n                    quoteprice = self.limit\r\n            def imbalance_alter(quoteprice, lob):\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n                level_1_ofi_cul = 0\r\n                level_2_ofi_cul = 0\r\n                level_3_ofi_cul = 0\r\n\r\n                n = 1\r\n                while (len(self.list_OFI) >= n):\r\n                    level_1_ofi_cul = level_1_ofi_cul + self.list_OFI[-n]['level1']\r\n                    level_2_ofi_cul = level_2_ofi_cul + self.list_OFI[-n]['level2']\r\n                    level_3_ofi_cul = level_3_ofi_cul + self.list_OFI[-n]['level3']\r\n                    n = n + 1\r\n                    if (n >= 6): break\r\n\r\n                level_1_depth_cul = 0;\r\n                level_2_depth_cul = 0;\r\n                level_3_depth_cul = 0;\r\n\r\n                m = 1\r\n                while (len(self.list_D) >= m):\r\n\r\n                    level_1_depth_cul = level_1_depth_cul + self.list_D[-m]['level1']\r\n                    level_2_depth_cul = level_2_depth_cul + self.list_D[-m]['level2']\r\n                    level_3_depth_cul = level_3_depth_cul + self.list_D[-m]['level3']\r\n                    m = m + 1\r\n                    if (m >= 4): break\r\n\r\n                # if(level_1_depth_cul==0): level_1_depth_cul = 10000\r\n                # if(level_2_depth_cul==0): level_2_depth_cul = 10000\r\n                # if(level_3_depth_cul==0): level_3_depth_cul = 10000\r\n                if m == 1:\r\n                    level_1_depth_averge = level_1_depth_cul + 1\r\n                    level_2_depth_averge = level_2_depth_cul + 1\r\n                    level_3_depth_averge = level_3_depth_cul + 1\r\n\r\n                else:\r\n                    level_1_depth_averge = level_1_depth_cul / (m - 1) + 1\r\n                    level_2_depth_averge = level_2_depth_cul / (m - 1) + 1\r\n                    level_3_depth_averge = level_3_depth_cul / (m - 1) + 1\r\n                c = 0.5\r\n                decay = 0.8\r\n\r\n                # print 'level_1_depth_averge is %s'%level_1_depth_averge\r\n                # print 'level_2_depth_averge is %s'%level_2_depth_averge\r\n                # print 'level_3_depth_averge is %s'%level_3_depth_averge\r\n                offset = level_1_ofi_cul * c / level_1_depth_averge + decay * level_2_ofi_cul * c / level_2_depth_averge + decay * decay * level_3_ofi_cul * c / level_3_depth_averge\r\n\r\n                # quoteprice_iaa = (quoteprice_aa+offset)*0.9 + 0.1*quoteprice_aa\r\n                benchmark = quoteprice;\r\n                if(lob['midprice'] != None):\r\n                        benchmark = lob['midprice']\r\n                        # print 'midprice is %d' % benchmark\r\n                # print 'benchmark = %d' % benchmark\r\n                quoteprice_isimple = benchmark + offset\r\n                if self.job == 'Bid' and quoteprice_isimple > self.limit:\r\n                    quoteprice_isimple = self.limit\r\n                if self.job == 'Ask' and quoteprice_isimple < self.limit:\r\n                    quoteprice_isimple = self.limit\r\n\r\n                # print 'IAA_MLOFI original quotaprice: %d' % (quoteprice)\r\n                # print 'offset is %d'%offset\r\n                # print 'level1 ofi is %d'%level_1_ofi_cul\r\n                # print 'level2 ofi is %d'%level_2_ofi_cul\r\n                # print 'level3 ofi is %d'%level_3_ofi_cul\r\n                # print 'level1 depth is %d'%level_1_depth_averge\r\n                # print 'level2 depth is %d'%level_2_depth_averge\r\n                # print 'level3 depth is %d'%level_3_depth_averge\r\n                # print 'offset is %d'%offset\r\n                # print 'IAA_MLOFI final quotaprice: %d' % (quoteprice_isimple)\r\n                # print 'IAAB_MLOFI JOB IS %s' % self.job\r\n                return quoteprice_isimple\r\n\r\n            quoteprice_isimple = imbalance_alter(quoteprice, lob)\r\n\r\n            order = Order(self.tid,\r\n                          self.orders[0].atype,\r\n                          'LIM',\r\n                          quoteprice_isimple,\r\n                          self.orders[0].qty,\r\n                          time, None, -1)\r\n            self.lastquote = order\r\n        return order\r\n\r\n    def respond(self, time, lob, trade, verbose):\r\n\r\n        ## End nicked from ZIP\r\n        if (self.last_lob == None):\r\n            self.last_lob = lob\r\n        else:\r\n            # print ''\r\n            # print ''\r\n            # print 'pre lob'\r\n            # print 'bid anon:'\r\n            # print self.last_lob['bids']['lob']\r\n            # print 'ask anon:'\r\n            # print self.last_lob['asks']['lob']\r\n            # print 'current lob'\r\n            # print 'bid anon:'\r\n            # print lob['bids']['lob']\r\n            # print 'ask anon:'\r\n            # print lob['asks']['lob']\r\n\r\n            self.cal_e(time, lob, trade, verbose)\r\n            self.cal_depth(lob);\r\n            self.last_lob = lob;\r\n\r\n\r\n"
  },
  {
    "path": "ZhenZhang/source/ZZISHV.py",
    "content": "\r\nfrom BSE2_msg_classes import Assignment, Order, Exch_msg\r\nfrom BSE_trader_agents import Trader;\r\nimport random\r\nimport math\r\nbse_sys_minprice = 1  # minimum price in the system, in cents/pennies\r\nbse_sys_maxprice = 200  # maximum price in the system, in cents/pennies\r\n\r\n\r\nclass Trader_ZZISHV(Trader):\r\n\r\n    def __init__(self, ttype, tid, balance, time,m):\r\n        Trader.__init__(self, ttype, tid, balance, time)\r\n        self.limit = None\r\n        self.job = None\r\n\r\n        # variable for MLOFI\r\n        self.last_lob = None;\r\n        self.es_list = [];\r\n        self.ds_list = [];\r\n\r\n        #variable for ratio\r\n        self.bids_volume_list = []\r\n        self.asks_volume_list = []\r\n\r\n        # m\r\n        self.m = m;\r\n\r\n\r\n\r\n    def is_imbalance_significant(self, m,threshold):\r\n        cb_list = [0 for i in range(m)]\r\n        ab_list = []\r\n\r\n        ca_list = [0 for i in range(m)]\r\n        aa_list = []\r\n\r\n        n = 1\r\n\r\n        while len(self.bids_volume_list) >= n and len(self.asks_volume_list) >= n:\r\n            for i in range(m):\r\n                cb_list[i] += self.bids_volume_list[-n]['level' + str(i + 1)]\r\n                ca_list[i] += self.asks_volume_list[-n]['level' + str(i + 1)]\r\n            n += 1\r\n            if n >= 11:\r\n                break\r\n\r\n\r\n        for i in range(m):\r\n            temp1 = None\r\n            temp2 = None\r\n            if n == 1:\r\n                temp1 = cb_list[i] + 1\r\n                temp2 = ca_list[i] + 1\r\n            else:\r\n                temp1 = cb_list[i] / (n - 1) + 1\r\n                temp2 = ca_list[i] / (n - 1) + 1\r\n            ab_list.append(temp1)\r\n            aa_list.append(temp2)\r\n\r\n        v_bid = 0;\r\n        v_ask = 0;\r\n        for i in range(m):\r\n            v_bid += math.exp(-0.5*i)*ab_list[i];\r\n            v_ask += math.exp(-0.5*i)*aa_list[i];\r\n        ratio = (v_bid-v_ask)/(v_bid+v_ask);\r\n\r\n        # print self.bids_volume_list\r\n        # print self.asks_volume_list\r\n        # print ratio\r\n\r\n        if(ratio>threshold or ratio<-threshold):\r\n            return True\r\n        else:\r\n            return False\r\n\r\n\r\n\r\n\r\n\r\n    def calc_bids_volume(self, lob, m, verbose):\r\n        new_b = {}\r\n\r\n        for i in range(1, m + 1):\r\n            new_b['level' + str(i)] = self.cal_bids_n(lob, i)\r\n\r\n        self.bids_volume_list.append(new_b)\r\n\r\n    def cal_bids_n(self, lob, n):\r\n\r\n        if (len(lob['bids']['lob']) < n):\r\n            r_n = 0\r\n        else:\r\n            r_n = lob['bids']['lob'][n - 1][1]\r\n\r\n        return r_n\r\n\r\n    def calc_asks_volume(self, lob, m, verbose):\r\n        new_a = {}\r\n\r\n        for i in range(1, m + 1):\r\n            new_a['level' + str(i)] = self.cal_asks_n(lob, i);\r\n\r\n        self.asks_volume_list.append(new_a)\r\n\r\n    def cal_asks_n(self, lob, n):\r\n\r\n        if (len(lob['asks']['lob']) < n):\r\n            q_n = 0\r\n        else:\r\n            q_n = lob['asks']['lob'][n - 1][1]\r\n        return q_n\r\n\r\n    def calc_level_n_e(self, current_lob, n):\r\n        b_n = 0\r\n        r_n = 0\r\n        a_n = 0\r\n        q_n = 0\r\n\r\n        b_n_1 = 0\r\n        r_n_1 = 0\r\n        a_n_1 = 0\r\n        q_n_1 = 0\r\n\r\n        if (len(current_lob['bids']['lob']) < n):\r\n            b_n = 0\r\n            r_n = 0\r\n        else:\r\n            b_n = current_lob['bids']['lob'][n - 1][0]\r\n            r_n = current_lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(self.last_lob['bids']['lob']) < n):\r\n            b_n_1 = 0\r\n            r_n_1 = 0\r\n        else:\r\n            b_n_1 = self.last_lob['bids']['lob'][n - 1][0]\r\n            r_n_1 = self.last_lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(current_lob['asks']['lob']) < n):\r\n            a_n = 0\r\n            q_n = 0\r\n        else:\r\n            a_n = current_lob['asks']['lob'][n - 1][0]\r\n            q_n = current_lob['asks']['lob'][n - 1][1]\r\n\r\n        if (len(self.last_lob['asks']['lob']) < n):\r\n            a_n_1 = 0\r\n            q_n_1 = 0\r\n        else:\r\n            a_n_1 = self.last_lob['asks']['lob'][n - 1][0]\r\n            q_n_1 = self.last_lob['asks']['lob'][n - 1][1]\r\n\r\n        delta_w = 0;\r\n\r\n        if (b_n > b_n_1):\r\n            delta_w = r_n\r\n        elif (b_n == b_n_1):\r\n            delta_w = r_n - r_n_1\r\n        else:\r\n            delta_w = -r_n_1\r\n\r\n        delta_v = 0\r\n        if (a_n > a_n_1):\r\n            delta_v = -q_n_1\r\n        elif (a_n == a_n_1):\r\n            delta_v = q_n - q_n_1\r\n        else:\r\n            delta_v = q_n\r\n\r\n        return delta_w - delta_v\r\n\r\n    def calc_es(self, lob, m, verbose):\r\n        new_e = {}\r\n        for i in range(1, m + 1):\r\n            new_e['level' + str(i)] = self.calc_level_n_e(lob, i)\r\n\r\n        self.es_list.append(new_e)\r\n\r\n    def calc_ds(self, lob, m, verbose):\r\n        new_d = {}\r\n\r\n        for i in range(1, m + 1):\r\n            new_d['level' + str(i)] = self.cal_depth_n(lob, i)\r\n\r\n        self.ds_list.append(new_d)\r\n\r\n    def cal_depth_n(self, lob, n):\r\n\r\n        if (len(lob['bids']['lob']) < n):\r\n            r_n = 0\r\n        else:\r\n            r_n = lob['bids']['lob'][n - 1][1]\r\n\r\n        if (len(lob['asks']['lob']) < n):\r\n            q_n = 0\r\n        else:\r\n            q_n = lob['asks']['lob'][n - 1][1]\r\n        return (r_n + q_n) / 2\r\n\r\n    def respond(self, time, lob, trade, verbose):\r\n        if (self.last_lob == None):\r\n            self.last_lob = lob\r\n        else:\r\n            self.calc_es(lob, self.m, verbose)\r\n            self.calc_ds(lob, self.m, verbose)\r\n            self.calc_bids_volume(lob, self.m, verbose)\r\n            self.calc_asks_volume(lob, self.m, verbose)\r\n            self.last_lob = lob\r\n\r\n\r\n    def getorder(self, time, countdown, lob, verbose):\r\n\r\n        if verbose: print(\"ISHV getorder:\")\r\n\r\n        shave_c = 2 # c in the y=mx+c linear mapping from imbalance to shave amount\r\n        shave_m = 1 # m in the y=mx+c\r\n\r\n        if len(self.orders) < 1:\r\n            order = None\r\n        else:\r\n            if verbose: print(\" self.orders[0]=%s\" % str(self.orders[0]))\r\n            self.limit = self.orders[0].price\r\n            self.job = self.orders[0].atype\r\n\r\n            otype = self.orders[0].atype\r\n            ostyle = self.orders[0].astyle\r\n\r\n            microp = lob['microprice']\r\n            midp = lob['midprice']\r\n\r\n            if otype == 'Bid':\r\n                if len(lob['bids']['lob']) > 0:\r\n                    quoteprice = lob['bids']['bestp']\r\n                    if quoteprice > self.limit :\r\n                        quoteprice = self.limit\r\n                else:\r\n                    quoteprice = 1  # KLUDGE -- come back to fix todo\r\n            else:\r\n\r\n                if len(lob['asks']['lob']) > 0:\r\n                    quoteprice = lob['asks']['bestp']\r\n                    if quoteprice < self.limit:\r\n                        quoteprice = self.limit\r\n                else:\r\n                    quoteprice = 200  # KLUDGE -- come back to fix todo\r\n\r\n\r\n\r\n\r\n            def imbalance_alter(quoteprice_aa, lob, countdown, m):\r\n\r\n                mlofi_list = [0 for i in range(m)]\r\n                cd_list = [0 for i in range(m)]\r\n                ad_list = []\r\n                n = 1\r\n\r\n                while len(self.es_list) >= n:\r\n                    for i in range(m):\r\n                        mlofi_list[i] += self.es_list[-n]['level' + str(i+1)]\r\n                    n += 1\r\n                    if n >= 11:\r\n                        break\r\n\r\n                n = 1\r\n\r\n                while len(self.ds_list) >= n:\r\n                    for i in range(m):\r\n                        cd_list[i] += self.ds_list[-n]['level' + str(i+1)]\r\n                    n += 1\r\n                    if n >= 11:\r\n                        break\r\n\r\n                for i in range(m):\r\n                    temp = None\r\n                    if n == 1:\r\n                        temp = cd_list[i]+1\r\n                    else:\r\n                        temp = cd_list[i]/(n-1)+1\r\n                    ad_list.append(temp)\r\n\r\n                c = 5\r\n                decay = 0.8\r\n                offset = 0\r\n\r\n                for i in range(m):\r\n                    offset += int(mlofi_list[i]*c*pow(decay,i)/ ad_list[i])\r\n\r\n\r\n                benchmark = quoteprice_aa;\r\n                if(lob['midprice'] != None):\r\n                        benchmark = lob['midprice']\r\n                # print 'midprice is %d' % benchmark\r\n\r\n                quoteprice_iaa = quoteprice_aa + 0.8 * (benchmark + offset - quoteprice_aa)\r\n                if self.job == 'Bid' and quoteprice_iaa > self.limit:\r\n                    quoteprice_iaa = self.limit\r\n                if self.job == 'Ask' and quoteprice_iaa < self.limit:\r\n                    quoteprice_iaa = self.limit\r\n\r\n                if countdown < 0.3 :\r\n                    print \"insert\"\r\n                    if self.job == 'Bid' and (len(lob['asks']['lob']) >= 1) and lob['asks']['lob'][0][0] < self.limit:\r\n                        quoteprice_iaa = lob['asks']['lob'][0][0]\r\n                    if self.job == 'Ask' and (len(lob['bids']['lob']) >= 1) and lob['bids']['lob'][0][0] > self.limit:\r\n                        quoteprice_iaa = lob['bids']['lob'][0][0]\r\n\r\n                return quoteprice_iaa\r\n\r\n            if(self.is_imbalance_significant(self.m,0.6)):\r\n                # print \"abvious\"\r\n                quoteprice_iaa = imbalance_alter(quoteprice, lob, countdown, self.m)\r\n\r\n            else:\r\n                # print \"not abvious\"\r\n                quoteprice_iaa = quoteprice\r\n\r\n\r\n\r\n            order = Order(self.tid, otype, ostyle, quoteprice_iaa, self.orders[0].qty, time, None, verbose)\r\n            self.lastquote = order\r\n        return order\r\n\r\n"
  },
  {
    "path": "ZhenZhang/source/dataAnalysis/box_analysis.py",
    "content": "\r\n\r\nimport numpy as np\r\nimport matplotlib.pyplot as plt\r\nimport csv\r\nfrom pylab import *\r\n# Fixing random state for reproducibility\r\nnp.random.seed(19680801)\r\n\r\ncsv_file = open(\"../Mybalances.csv\",\"r\")\r\ncsv_reader = csv.reader(csv_file);\r\n\r\ny1 = []\r\ny2 = []\r\ny3 = []\r\ny4 = []\r\nname1 = None\r\nname2 = None\r\nname3 = None\r\nname4 = None\r\n\r\ncy1 = 0;\r\ncy2 = 0;\r\ncy3 = 0;\r\ncy4 = 0;\r\ncount = 0\r\nfor item in csv_reader:\r\n    y1.append(int(float(item[5])))\r\n    # y2.append(int(float(item[13])))\r\n    # cy1 += int(float(item[5]))\r\n    # cy2 += int(float(item[13]))\r\n\r\n\r\n\r\n    y3.append(int(float(item[17])))\r\n    #y4.append(int(float(item[21])))\r\n\r\n    # y3.append(int(float(item[13])))\r\n    # y4.append(int(float(item[17])))\r\n    # name1 = item[2]\r\n    # name2 = item[6]\r\n    # name3 = item[10]\r\n    # name4 = item[14]\r\n    # print '%s,%s'%(item[5],item[9])\r\n    count += 1\r\n\r\n\r\n\r\n\r\n\r\n\r\nfig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(10, 8))\r\n\r\n\r\ndata = [y1,y3]\r\nnames = ['AA','IAA']\r\n\r\n\r\nax1.set_title('(a) The daily profits for different agents')\r\ngreen_diamond = dict(markerfacecolor='g', marker='D')\r\ndp1= ax1.boxplot(data,vert=True,whis=0.75,notch=False, labels=names,showmeans=True,meanline=False,meanprops=green_diamond)\r\n\r\n\r\n\r\n\r\nx1,y = dp1['medians'][0].get_xydata()[1]\r\nax1.text(x1+0.075, y, '%.1f' % y,horizontalalignment='left')\r\nx2,y = dp1['medians'][1].get_xydata()[1]\r\nax1.text(x2+0.075, y, '%.1f' % y,horizontalalignment='left')\r\n\r\n# for line in dp1['medians']:\r\n#     # get position data for median line\r\n#     x, y = line.get_xydata()[1] # top of median line\r\n#     # overlay median value\r\n#     print x\r\n#     print y\r\n#     ax1.text(x+0.125, y, '%.1f' % y,horizontalalignment='left')\r\n\r\n\r\nfor index in range(len(dp1['means'])):\r\n    y = dp1['means'][index].get_ydata()[0]\r\n    if index==0:\r\n        ax1.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==1:\r\n        ax1.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n\r\n\r\n\r\nfor index in range(len(dp1['boxes'])):\r\n    y = dp1['boxes'][index].get_ydata()[0]\r\n    if index==0:\r\n        ax1.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==1:\r\n        ax1.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n\r\n    y = dp1['boxes'][index].get_ydata()[2]\r\n    if index==0:\r\n        ax1.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    # elif index ==1:\r\n    #     ax1.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n\r\n\r\n# for index in range(len(dp1['boxes'])):\r\n#\r\n#     y = dp1['boxes'][index].get_ydata()[0]\r\n#\r\n#     if index==0:\r\n#         ax1.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n#     elif index ==1:\r\n#         ax1.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n#\r\n#     y = dp1['boxes'][index].get_ydata()[2]\r\n#\r\n#     if index==0:\r\n#         ax1.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n#     elif index ==1:\r\n#         ax1.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n\r\n\r\nfor index in range(len(dp1['caps'])):\r\n    print 'one round'\r\n    print index\r\n    y = dp1['caps'][index].get_ydata()[0]\r\n    print 'bottom'\r\n    print y\r\n    if index==0:\r\n        ax1.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==1:\r\n        ax1.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==2:\r\n        ax1.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==3:\r\n        ax1.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n\r\n    # y = dp1['caps'][index].get_ydata()[1]\r\n    # print 'top'\r\n    # print y\r\n    # if index==0:\r\n    #     ax1.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    # elif index ==1:\r\n    #     ax1.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n# for line in dp1['means']:\r\n#     # get position data for median line\r\n#     x, y = line.get_ydata()[0] # top of median line\r\n#     # overlay median value\r\n#     print x\r\n#     print y\r\n#     ax1.text(x+0.125, y, '%.1f' % y,horizontalalignment='left')\r\n#\r\n# print 'boxes'\r\n#\r\n# for line in dp1['boxes']:\r\n#\r\n#     x, y = line.get_xydata()[0] # bottom of left line\r\n#     ax1.text(x+0.125,y, '%.1f' % y,horizontalalignment='right')      # below\r\n#     x, y = line.get_xydata()[2] # bottom of right line\r\n#     ax1.text(x+0.125,y, '%.1f' % y,horizontalalignment='right')      # below\r\n\r\n\r\n\r\n\r\ndif1 = []\r\nfor i in range(len(y1)):\r\n    dif1.append(y3[i]-y1[i])\r\n\r\n\r\nax2.set_title('(b) The profit differences for different agents')\r\ndp2 = ax2.boxplot(dif1,vert=True,whis=0.75,notch=False, showmeans=True,labels=['IAA-AA'],meanprops=green_diamond)\r\n\r\nx1,y = dp2['medians'][0].get_xydata()[1]\r\nax2.text(x1+0.075, y, '%.1f' % y,horizontalalignment='left')\r\n# x2,y = dp1['medians'][1].get_xydata()[1]\r\n# ax1.text(x2+0.075, y, '%.1f' % y,horizontalalignment='left')\r\n\r\n# for line in dp1['medians']:\r\n#     # get position data for median line\r\n#     x, y = line.get_xydata()[1] # top of median line\r\n#     # overlay median value\r\n#     print x\r\n#     print y\r\n#     ax1.text(x+0.125, y, '%.1f' % y,horizontalalignment='left')\r\n\r\n\r\nfor index in range(len(dp2['means'])):\r\n    y = dp2['means'][index].get_ydata()[0]\r\n    if index==0:\r\n        ax2.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==1:\r\n        ax2.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n\r\n\r\n\r\nfor index in range(len(dp2['boxes'])):\r\n    y = dp2['boxes'][index].get_ydata()[0]\r\n    if index==0:\r\n        ax2.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==1:\r\n        ax2.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n\r\n    y = dp2['boxes'][index].get_ydata()[2]\r\n    if index==0:\r\n        ax2.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==1:\r\n        ax2.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n\r\n\r\nfor index in range(len(dp2['boxes'])):\r\n\r\n    y = dp2['boxes'][index].get_ydata()[0]\r\n\r\n    if index==0:\r\n        ax2.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==1:\r\n        ax2.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n\r\n    y = dp2['boxes'][index].get_ydata()[2]\r\n\r\n    if index==0:\r\n        ax2.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==1:\r\n        ax2.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n\r\n\r\nfor index in range(len(dp2['caps'])):\r\n    print 'one round'\r\n    print index\r\n    y = dp2['caps'][index].get_ydata()[0]\r\n    print 'bottom'\r\n    print y\r\n    if index==0:\r\n        ax2.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==1:\r\n        ax2.text(x1 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==2:\r\n        ax2.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n    elif index ==3:\r\n        ax2.text(x2 + 0.075, y, '%.1f' % y, horizontalalignment='left')\r\n\r\n\r\n\r\n\r\nplt.savefig(\"./box1.png\")\r\n\r\n\r\n# # fake up some data\r\n# spread = np.random.rand(50) * 100\r\n# center = np.ones(25) * 50\r\n# flier_high = np.random.rand(10) * 100 + 100\r\n# flier_low = np.random.rand(10) * -100\r\n# data = np.concatenate((spread, center, flier_high, flier_low))\r\n#\r\n# fig1, ax1 = plt.subplots()\r\n# ax1.set_title('Basic Plot')\r\n# ax1.boxplot(data,vert=False)\r\n#\r\n#\r\n# spread = np.random.rand(50) * 100\r\n# center = np.ones(25) * 40\r\n# flier_high = np.random.rand(10) * 100 + 100\r\n# flier_low = np.random.rand(10) * -100\r\n# d2 = np.concatenate((spread, center, flier_high, flier_low))\r\n# data.shape = (-1, 1)\r\n# d2.shape = (-1, 1)\r\n#\r\n# data = [data, d2, d2[::2,0]]\r\n# fig7, ax7 = plt.subplots()\r\n# ax7.set_title('Multiple Samples with Different sizes')\r\n# ax7.boxplot(data,vert=False)\r\n#\r\n# plt.show()"
  },
  {
    "path": "ZhenZhang/source/dataAnalysis/hypothesisTest.py",
    "content": "\r\n\r\n\r\nimport scipy.stats as stats\r\nimport csv\r\ncsv_file = open(\"../Mybalances.csv\",\"r\")\r\ncsv_reader = csv.reader(csv_file);\r\n\r\ny1 = []\r\ny2 = []\r\ny3 = []\r\ny4 = []\r\nname1 = None\r\nname2 = None\r\nname3 = None\r\nname4 = None\r\n\r\n\r\ncount = 0\r\nfor item in csv_reader:\r\n    y1.append(float(item[5]))\r\n    y2.append(float(item[17]))\r\n    # y3.append(int(float(item[13])))\r\n    # y4.append(int(float(item[17])))\r\n    name1 = item[2]\r\n    name2 = item[14]\r\n    # name3 = item[10]\r\n    # name4 = item[14]\r\n    # print '%s,%s'%(item[5],item[9])\r\n    count += 1\r\n\r\n\r\nu_statistic, pVal = stats.mannwhitneyu(y1, y2,alternative='less')\r\n\r\nprint \"u_statistic is %f\"%u_statistic;\r\nprint \"p value is %f\"%pVal;\r\n\r\n\r\nimport numpy as np\r\n#create 95% confidence interval for population mean weight\r\nprint np.mean(y2)\r\nprint stats.t.interval(alpha=0.95, df=len(y2)-1, loc=np.mean(y2), scale=stats.sem(y2))[1] - np.mean(y2)\r\nprint \"\"\r\nprint np.mean(y1)\r\nprint stats.t.interval(alpha=0.95, df=len(y1)-1, loc=np.mean(y1), scale=stats.sem(y1))[1] - np.mean(y1)\r\nprint \"\"\r\n\r\ndf = []\r\n\r\nfor index in range(len(y1)):\r\n    df.append(y2[index]-y1[index])\r\nprint np.mean(df)\r\nprint stats.t.interval(alpha=0.95, df=len(df)-1, loc=np.mean(df), scale=stats.sem(df))[1] - np.mean(df)\r\n\r\n"
  },
  {
    "path": "ZhenZhang/source/dataAnalysis/matplotlib4.py",
    "content": "\r\n\r\nfrom matplotlib import pyplot as plot\r\nimport csv\r\nimport random\r\n\r\n\r\n\r\n\r\n\r\n\r\ncsv_file = open(\"../Mybalances.csv\",\"r\")\r\ncsv_reader = csv.reader(csv_file);\r\n\r\ny1 = []\r\ny2 = []\r\ny3 = []\r\ny4 = []\r\nname1 = None\r\nname2 = None\r\nname3 = None\r\nname4 = None\r\n\r\ncy1 = 0;\r\ncy2 = 0;\r\ncount = 0\r\nfor item in csv_reader:\r\n    y1.append(int(float(item[5])))\r\n    y2.append(int(float(item[17])))\r\n    cy1 += int(float(item[5]))\r\n    cy2 += int(float(item[17]))\r\n    # y3.append(int(float(item[13])))\r\n    # y4.append(int(float(item[17])))\r\n    name1 = item[2]\r\n    name2 = item[14]\r\n    # name3 = item[10]\r\n    # name4 = item[14]\r\n    # print '%s,%s'%(item[5],item[9])\r\n    count += 1\r\nx = range(1,count+1)\r\nfig, ax = plot.subplots()\r\n\r\ncost1 = cy1/count\r\ncost1_list = [cost1 for i in range(1,count+1)]\r\n\r\ncost2 = cy2/count\r\ncost2_list = [cost2 for i in range(1,count+1)]\r\n\r\nax.plot(x,y1,label=\"AA\")\r\nax.plot(x,y2,label=\"IAA\")\r\nax.plot(x,cost1_list,linestyle=\"dashed\", label= \"AA's average profit = \"+str(float((cy1+0.0)/count)))\r\nax.plot(x,cost2_list,linestyle=\"dashed\", label= \"IAA's average profit = \"+str(float((cy2+0.0)/count)))\r\n# ax.plot(x,y3,label=name3)\r\n# ax.plot(x,y4,label=name4)\r\n\r\n# xticks_label  =  [i*5 for i in range(1,21)]\r\n# plot.xticks( xticks_label)\r\n# yticks_label  =  [i*5 for i in range(10,30)]\r\n# plot.yticks( yticks_label)\r\nax.set_xlabel('trading day')\r\nax.set_ylabel('total profit in each trading day')\r\nax.legend()\r\nplot.savefig(\"./balance4.png\")\r\n\r\n"
  },
  {
    "path": "clean.sh",
    "content": "rm *.csv\n"
  },
  {
    "path": "snashall2019.py",
    "content": "# -*- coding: utf-8 -*-\r\n#\r\n# BSE: The Bristol Stock Exchange\r\n#\r\n# Version 1.3; July 21st, 2018.\r\n# Version 1.2; November 17th, 2012.\r\n#\r\n# Copyright (c) 2012-2018, Dave Cliff\r\n#\r\n#\r\n# ------------------------\r\n#\r\n# MIT Open-Source License:\r\n# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and\r\n# associated documentation files (the \"Software\"), to deal in the Software without restriction,\r\n# including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\r\n# and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,\r\n# subject to the following conditions:\r\n#\r\n# The above copyright notice and this permission notice shall be included in all copies or substantial\r\n# portions of the Software.\r\n#\r\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT\r\n# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r\n# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n#\r\n# ------------------------\r\n#\r\n#\r\n#\r\n# BSE is a very simple simulation of automated execution traders\r\n# operating on a very simple model of a limit order book (LOB) exchange\r\n#\r\n# major simplifications in this version:\r\n#       (a) only one financial instrument being traded\r\n#       (b) traders can only trade contracts of size 1 (will add variable quantities later)\r\n#       (c) each trader can have max of one order per single orderbook.\r\n#       (d) traders can replace/overwrite earlier orders, and/or can cancel\r\n#       (d) simply processes each order in sequence and republishes LOB to all traders\r\n#           => no issues with exchange processing latency/delays or simultaneously issued orders.\r\n#\r\n# NB this code has been written to be readable/intelligible, not efficient!\r\n\r\n# could import pylab here for graphing etc\r\n\r\nimport sys\r\nimport math\r\nimport random\r\n\r\n\r\nbse_sys_minprice = 1  # minimum price in the system, in cents/pennies\r\nbse_sys_maxprice = 1000  # maximum price in the system, in cents/pennies\r\nticksize = 1  # minimum change in price, in cents/pennies\r\n\r\n\r\n\r\n# an Order/quote has a trader id, a type (buy/sell) price, quantity, timestamp, and unique i.d.\r\nclass Order:\r\n\r\n        def __init__(self, tid, otype, price, qty, time, qid):\r\n                self.tid = tid      # trader i.d.\r\n                self.otype = otype  # order type\r\n                self.price = price  # price\r\n                self.qty = qty      # quantity\r\n                self.time = time    # timestamp\r\n                self.qid = qid      # quote i.d. (unique to each quote)\r\n\r\n        def __str__(self):\r\n                return '[%s %s P=%03d Q=%s T=%5.2f QID:%d]' % \\\r\n                       (self.tid, self.otype, self.price, self.qty, self.time, self.qid)\r\n\r\n\r\n\r\n# Orderbook_half is one side of the book: a list of bids or a list of asks, each sorted best-first\r\n\r\nclass Orderbook_half:\r\n\r\n        def __init__(self, booktype, worstprice):\r\n                # booktype: bids or asks?\r\n                self.booktype = booktype\r\n                # dictionary of orders received, indexed by Trader ID\r\n                self.orders = {}\r\n                # limit order book, dictionary indexed by price, with order info\r\n                self.lob = {}\r\n                # anonymized LOB, lists, with only price/qty info\r\n                self.lob_anon = []\r\n                # summary stats\r\n                self.best_price = None\r\n                self.best_tid = None\r\n                self.worstprice = worstprice\r\n                self.n_orders = 0  # how many orders?\r\n                self.lob_depth = 0  # how many different prices on lob?\r\n\r\n\r\n        def anonymize_lob(self):\r\n                # anonymize a lob, strip out order details, format as a sorted list\r\n                # NB for asks, the sorting should be reversed\r\n                self.lob_anon = []\r\n                for price in sorted(self.lob):\r\n                        qty = self.lob[price][0]\r\n                        self.lob_anon.append([price, qty])\r\n\r\n\r\n        def build_lob(self):\r\n                lob_verbose = False\r\n                # take a list of orders and build a limit-order-book (lob) from it\r\n                # NB the exchange needs to know arrival times and trader-id associated with each order\r\n                # returns lob as a dictionary (i.e., unsorted)\r\n                # also builds anonymized version (just price/quantity, sorted, as a list) for publishing to traders\r\n                self.lob = {}\r\n                for tid in self.orders:\r\n                        order = self.orders.get(tid)\r\n                        price = order.price\r\n                        if price in self.lob:\r\n                                # update existing entry\r\n                                qty = self.lob[price][0]\r\n                                orderlist = self.lob[price][1]\r\n                                orderlist.append([order.time, order.qty, order.tid, order.qid])\r\n                                self.lob[price] = [qty + order.qty, orderlist]\r\n                        else:\r\n                                # create a new dictionary entry\r\n                                self.lob[price] = [order.qty, [[order.time, order.qty, order.tid, order.qid]]]\r\n                # create anonymized version\r\n                self.anonymize_lob()\r\n                # record best price and associated trader-id\r\n                if len(self.lob) > 0 :\r\n                        if self.booktype == 'Bid':\r\n                                self.best_price = self.lob_anon[-1][0]\r\n                        else :\r\n                                self.best_price = self.lob_anon[0][0]\r\n                        self.best_tid = self.lob[self.best_price][1][0][2]\r\n                else :\r\n                        self.best_price = None\r\n                        self.best_tid = None\r\n\r\n                if lob_verbose : print self.lob\r\n\r\n\r\n        def book_add(self, order):\r\n                # add order to the dictionary holding the list of orders\r\n                # either overwrites old order from this trader\r\n                # or dynamically creates new entry in the dictionary\r\n                # so, max of one order per trader per list\r\n                # checks whether length or order list has changed, to distinguish addition/overwrite\r\n                #print('book_add > %s %s' % (order, self.orders))\r\n                n_orders = self.n_orders\r\n                self.orders[order.tid] = order\r\n                self.n_orders = len(self.orders)\r\n                self.build_lob()\r\n                #print('book_add < %s %s' % (order, self.orders))\r\n                if n_orders != self.n_orders :\r\n                    return('Addition')\r\n                else:\r\n                    return('Overwrite')\r\n\r\n\r\n\r\n        def book_del(self, order):\r\n                # delete order from the dictionary holding the orders\r\n                # assumes max of one order per trader per list\r\n                # checks that the Trader ID does actually exist in the dict before deletion\r\n                # print('book_del %s',self.orders)\r\n                if self.orders.get(order.tid) != None :\r\n                        del(self.orders[order.tid])\r\n                        self.n_orders = len(self.orders)\r\n                        self.build_lob()\r\n                # print('book_del %s', self.orders)\r\n\r\n\r\n        def delete_best(self):\r\n                # delete order: when the best bid/ask has been hit, delete it from the book\r\n                # the TraderID of the deleted order is return-value, as counterparty to the trade\r\n                best_price_orders = self.lob[self.best_price]\r\n                best_price_qty = best_price_orders[0]\r\n                best_price_counterparty = best_price_orders[1][0][2]\r\n                if best_price_qty == 1:\r\n                        # here the order deletes the best price\r\n                        del(self.lob[self.best_price])\r\n                        del(self.orders[best_price_counterparty])\r\n                        self.n_orders = self.n_orders - 1\r\n                        if self.n_orders > 0:\r\n                                if self.booktype == 'Bid':\r\n                                        self.best_price = max(self.lob.keys())\r\n                                else:\r\n                                        self.best_price = min(self.lob.keys())\r\n                                self.lob_depth = len(self.lob.keys())\r\n                        else:\r\n                                self.best_price = self.worstprice\r\n                                self.lob_depth = 0\r\n                else:\r\n                        # best_bid_qty>1 so the order decrements the quantity of the best bid\r\n                        # update the lob with the decremented order data\r\n                        self.lob[self.best_price] = [best_price_qty - 1, best_price_orders[1][1:]]\r\n\r\n                        # update the bid list: counterparty's bid has been deleted\r\n                        del(self.orders[best_price_counterparty])\r\n                        self.n_orders = self.n_orders - 1\r\n                self.build_lob()\r\n                return best_price_counterparty\r\n\r\n\r\n\r\n# Orderbook for a single instrument: list of bids and list of asks\r\n\r\nclass Orderbook(Orderbook_half):\r\n\r\n        def __init__(self):\r\n                self.bids = Orderbook_half('Bid', bse_sys_minprice)\r\n                self.asks = Orderbook_half('Ask', bse_sys_maxprice)\r\n                self.tape = []\r\n                self.quote_id = 0  #unique ID code for each quote accepted onto the book\r\n\r\n\r\n\r\n# Exchange's internal orderbook\r\n\r\nclass Exchange(Orderbook):\r\n\r\n        def add_order(self, order, verbose):\r\n                # add a quote/order to the exchange and update all internal records; return unique i.d.\r\n                order.qid = self.quote_id\r\n                self.quote_id = order.qid + 1\r\n                # if verbose : print('QUID: order.quid=%d self.quote.id=%d' % (order.qid, self.quote_id))\r\n                tid = order.tid\r\n                if order.otype == 'Bid':\r\n                        response=self.bids.book_add(order)\r\n                        best_price = self.bids.lob_anon[-1][0]\r\n                        self.bids.best_price = best_price\r\n                        self.bids.best_tid = self.bids.lob[best_price][1][0][2]\r\n                else:\r\n                        response=self.asks.book_add(order)\r\n                        best_price = self.asks.lob_anon[0][0]\r\n                        self.asks.best_price = best_price\r\n                        self.asks.best_tid = self.asks.lob[best_price][1][0][2]\r\n                return [order.qid, response]\r\n\r\n\r\n        def del_order(self, time, order, verbose):\r\n                # delete a trader's quot/order from the exchange, update all internal records\r\n                tid = order.tid\r\n                if order.otype == 'Bid':\r\n                        self.bids.book_del(order)\r\n                        if self.bids.n_orders > 0 :\r\n                                best_price = self.bids.lob_anon[-1][0]\r\n                                self.bids.best_price = best_price\r\n                                self.bids.best_tid = self.bids.lob[best_price][1][0][2]\r\n                        else: # this side of book is empty\r\n                                self.bids.best_price = None\r\n                                self.bids.best_tid = None\r\n                        cancel_record = { 'type': 'Cancel', 'time': time, 'order': order }\r\n                        self.tape.append(cancel_record)\r\n\r\n                elif order.otype == 'Ask':\r\n                        self.asks.book_del(order)\r\n                        if self.asks.n_orders > 0 :\r\n                                best_price = self.asks.lob_anon[0][0]\r\n                                self.asks.best_price = best_price\r\n                                self.asks.best_tid = self.asks.lob[best_price][1][0][2]\r\n                        else: # this side of book is empty\r\n                                self.asks.best_price = None\r\n                                self.asks.best_tid = None\r\n                        cancel_record = { 'type': 'Cancel', 'time': time, 'order': order }\r\n                        self.tape.append(cancel_record)\r\n                else:\r\n                        # neither bid nor ask?\r\n                        sys.exit('bad order type in del_quote()')\r\n\r\n\r\n\r\n        def process_order2(self, time, order, verbose):\r\n                # receive an order and either add it to the relevant LOB (ie treat as limit order)\r\n                # or if it crosses the best counterparty offer, execute it (treat as a market order)\r\n                oprice = order.price\r\n                counterparty = None\r\n                [qid, response] = self.add_order(order, verbose)  # add it to the order lists -- overwriting any previous order\r\n                order.qid = qid\r\n                if verbose :\r\n                        print('QUID: order.quid=%d' % order.qid)\r\n                        print('RESPONSE: %s' % response)\r\n                best_ask = self.asks.best_price\r\n                best_ask_tid = self.asks.best_tid\r\n                best_bid = self.bids.best_price\r\n                best_bid_tid = self.bids.best_tid\r\n                if order.otype == 'Bid':\r\n                        if self.asks.n_orders > 0 and best_bid >= best_ask:\r\n                                # bid lifts the best ask\r\n                                if verbose: print(\"Bid $%s lifts best ask\" % oprice)\r\n                                counterparty = best_ask_tid\r\n                                price = best_ask  # bid crossed ask, so use ask price\r\n                                if verbose: print('counterparty, price', counterparty, price)\r\n                                # delete the ask just crossed\r\n                                self.asks.delete_best()\r\n                                # delete the bid that was the latest order\r\n                                self.bids.delete_best()\r\n                elif order.otype == 'Ask':\r\n                        if self.bids.n_orders > 0 and best_ask <= best_bid:\r\n                                # ask hits the best bid\r\n                                if verbose: print(\"Ask $%s hits best bid\" % oprice)\r\n                                # remove the best bid\r\n                                counterparty = best_bid_tid\r\n                                price = best_bid  # ask crossed bid, so use bid price\r\n                                if verbose: print('counterparty, price', counterparty, price)\r\n                                # delete the bid just crossed, from the exchange's records\r\n                                self.bids.delete_best()\r\n                                # delete the ask that was the latest order, from the exchange's records\r\n                                self.asks.delete_best()\r\n                else:\r\n                        # we should never get here\r\n                        sys.exit('process_order() given neither Bid nor Ask')\r\n                # NB at this point we have deleted the order from the exchange's records\r\n                # but the two traders concerned still have to be notified\r\n                if verbose: print('counterparty %s' % counterparty)\r\n                if counterparty != None:\r\n                        # process the trade\r\n                        if verbose: print('>>>>>>>>>>>>>>>>>TRADE t=%5.2f $%d %s %s' % (time, price, counterparty, order.tid))\r\n                        transaction_record = { 'type': 'Trade',\r\n                                               'time': time,\r\n                                               'price': price,\r\n                                               'party1':counterparty,\r\n                                               'party2':order.tid,\r\n                                               'qty': order.qty\r\n                                              }\r\n                        self.tape.append(transaction_record)\r\n                        return transaction_record\r\n                else:\r\n                        return None\r\n\r\n\r\n\r\n        def tape_dump(self, fname, fmode, tmode):\r\n                dumpfile = open(fname, fmode)\r\n                for tapeitem in self.tape:\r\n                        if tapeitem['type'] == 'Trade' :\r\n                                dumpfile.write('%s, %s\\n' % (tapeitem['time'], tapeitem['price']))\r\n                dumpfile.close()\r\n                if tmode == 'wipe':\r\n                        self.tape = []\r\n\r\n\r\n        # this returns the LOB data \"published\" by the exchange,\r\n        # i.e., what is accessible to the traders\r\n        def publish_lob(self, time, verbose):\r\n                public_data = {}\r\n                public_data['time'] = time\r\n                public_data['bids'] = {'best':self.bids.best_price,\r\n                                     'worst':self.bids.worstprice,\r\n                                     'n': self.bids.n_orders,\r\n                                     'lob':self.bids.lob_anon}\r\n                public_data['asks'] = {'best':self.asks.best_price,\r\n                                     'worst':self.asks.worstprice,\r\n                                     'n': self.asks.n_orders,\r\n                                     'lob':self.asks.lob_anon}\r\n                public_data['QID'] = self.quote_id\r\n                public_data['tape'] = self.tape\r\n                if verbose:\r\n                        print('publish_lob: t=%d' % time)\r\n                        print('BID_lob=%s' % public_data['bids']['lob'])\r\n                        # print('best=%s; worst=%s; n=%s ' % (self.bids.best_price, self.bids.worstprice, self.bids.n_orders))\r\n                        print('ASK_lob=%s' % public_data['asks']['lob'])\r\n                        # print('qid=%d' % self.quote_id)\r\n\r\n                return public_data\r\n\r\n\r\n\r\n\r\n\r\n\r\n##################--Traders below here--#############\r\n\r\n\r\n# Trader superclass\r\n# all Traders have a trader id, bank balance, blotter, and list of orders to execute\r\nclass Trader:\r\n\r\n        def __init__(self, ttype, tid, balance, time):\r\n                self.ttype = ttype      # what type / strategy this trader is\r\n                self.tid = tid          # trader unique ID code\r\n                self.balance = balance  # money in the bank\r\n                self.blotter = []       # record of trades executed\r\n                self.orders = []        # customer orders currently being worked (fixed at 1)\r\n                self.n_quotes = 0       # number of quotes live on LOB\r\n                self.willing = 1        # used in ZIP etc\r\n                self.able = 1           # used in ZIP etc\r\n                self.birthtime = time   # used when calculating age of a trader/strategy\r\n                self.profitpertime = 0  # profit per unit time\r\n                self.n_trades = 0       # how many trades has this trader done?\r\n                self.lastquote = None   # record of what its last quote was\r\n\r\n\r\n        def __str__(self):\r\n                return '[TID %s type %s balance %s blotter %s orders %s n_trades %s profitpertime %s]' \\\r\n                       % (self.tid, self.ttype, self.balance, self.blotter, self.orders, self.n_trades, self.profitpertime)\r\n\r\n\r\n        def add_order(self, order, verbose):\r\n                # in this version, trader has at most one order,\r\n                # if allow more than one, this needs to be self.orders.append(order)\r\n                if self.n_quotes > 0 :\r\n                    # this trader has a live quote on the LOB, from a previous customer order\r\n                    # need response to signal cancellation/withdrawal of that quote\r\n                    response = 'LOB_Cancel'\r\n                else:\r\n                    response = 'Proceed'\r\n                self.orders = [order]\r\n                if verbose : print('add_order < response=%s' % response)\r\n                return response\r\n\r\n\r\n        def del_order(self, order):\r\n                # this is lazy: assumes each trader has only one customer order with quantity=1, so deleting sole order\r\n                # CHANGE TO DELETE THE HEAD OF THE LIST AND KEEP THE TAIL\r\n                self.orders = []\r\n\r\n\r\n        def bookkeep(self, trade, order, verbose, time):\r\n\r\n                outstr=\"\"\r\n                for order in self.orders: outstr = outstr + str(order)\r\n\r\n                self.blotter.append(trade)  # add trade record to trader's blotter\r\n                # NB What follows is **LAZY** -- assumes all orders are quantity=1\r\n                transactionprice = trade['price']\r\n                if self.orders[0].otype == 'Bid':\r\n                        profit = self.orders[0].price - transactionprice\r\n                else:\r\n                        profit = transactionprice - self.orders[0].price\r\n                self.balance += profit\r\n                self.n_trades += 1\r\n                self.profitpertime = self.balance/(time - self.birthtime)\r\n\r\n                if profit < 0 :\r\n                        print profit\r\n                        print trade\r\n                        print order\r\n                        sys.exit()\r\n\r\n                if verbose: print('%s profit=%d balance=%d profit/time=%d' % (outstr, profit, self.balance, self.profitpertime))\r\n                self.del_order(order)  # delete the order\r\n\r\n\r\n        # specify how trader responds to events in the market\r\n        # this is a null action, expect it to be overloaded by specific algos\r\n        def respond(self, time, lob, trade, verbose):\r\n                return None\r\n\r\n        # specify how trader mutates its parameter values\r\n        # this is a null action, expect it to be overloaded by specific algos\r\n        def mutate(self, time, lob, trade, verbose):\r\n                return None\r\n\r\n\r\n\r\n# Trader subclass Giveaway\r\n# even dumber than a ZI-U: just give the deal away\r\n# (but never makes a loss)\r\nclass Trader_Giveaway(Trader):\r\n\r\n        def getorder(self, time, countdown, lob):\r\n                if len(self.orders) < 1:\r\n                        order = None\r\n                else:\r\n                        quoteprice = self.orders[0].price\r\n                        order = Order(self.tid,\r\n                                    self.orders[0].otype,\r\n                                    quoteprice,\r\n                                    self.orders[0].qty,\r\n                                    time, lob['QID'])\r\n                        self.lastquote=order\r\n                return order\r\n\r\n# Trader subclass AA\r\nclass Trader_AA(Trader):\r\n\r\n        def __init__(self, ttype, tid, balance, time):\r\n                # Stuff about trader\r\n                self.ttype = ttype\r\n                self.tid = tid\r\n                self.balance = balance\r\n                self.birthtime = time\r\n                self.profitpertime = 0\r\n                self.n_trades = 0\r\n                self.blotter = []\r\n                self.orders = []\r\n                self.n_quotes = 0\r\n                self.lastquote = None\r\n\r\n                self.limit = None\r\n                self.job = None\r\n\r\n                # learning variables\r\n                self.r_shout_change_relative = 0.05\r\n                self.r_shout_change_absolute = 0.05\r\n                self.short_term_learning_rate = random.uniform(0.1, 0.5)\r\n                self.long_term_learning_rate = random.uniform(0.1, 0.5)\r\n                self.moving_average_weight_decay = 0.95 # how fast weight decays with time, lower is quicker, 0.9 in vytelingum\r\n                self.moving_average_window_size = 5\r\n                self.offer_change_rate = 3.0\r\n                self.theta = -2.0\r\n                self.theta_max = 2.0\r\n                self.theta_min = -8.0\r\n                self.marketMax = bse_sys_maxprice\r\n\r\n                # Variables to describe the market\r\n                self.previous_transactions = []\r\n                self.moving_average_weights = []\r\n                for i in range(self.moving_average_window_size):\r\n                        self.moving_average_weights.append(self.moving_average_weight_decay**i)\r\n                self.estimated_equilibrium = []\r\n                self.smiths_alpha = []\r\n                self.prev_best_bid_p = None\r\n                self.prev_best_bid_q = None\r\n                self.prev_best_ask_p = None\r\n                self.prev_best_ask_q = None\r\n\r\n                # Trading Variables\r\n                self.r_shout = None\r\n                self.buy_target = None\r\n                self.sell_target = None\r\n                self.buy_r = -1.0 * (0.3 * random.random())\r\n                self.sell_r = -1.0 * (0.3 * random.random())\r\n\r\n\r\n\r\n        def calcEq(self):\r\n                # Slightly modified from paper, it is unclear inpaper\r\n                # N previous transactions * weights / N in vytelingum, swap N denominator for sum of weights to be correct?\r\n                if len(self.previous_transactions) == 0:\r\n                        return\r\n                elif len(self.previous_transactions) < self.moving_average_window_size:\r\n                        # Not enough transactions\r\n                        self.estimated_equilibrium.append(float(sum(self.previous_transactions)) / max(len(self.previous_transactions), 1))\r\n                else:\r\n                        N_previous_transactions = self.previous_transactions[-self.moving_average_window_size:]\r\n                        thing = [N_previous_transactions[i]*self.moving_average_weights[i] for i in range(self.moving_average_window_size)]\r\n                        eq = sum( thing ) / sum(self.moving_average_weights)\r\n                        self.estimated_equilibrium.append(eq)\r\n\r\n        def calcAlpha(self):\r\n                alpha = 0.0\r\n                for p in self.estimated_equilibrium:\r\n                        alpha += (p - self.estimated_equilibrium[-1])**2\r\n                alpha = math.sqrt(alpha/len(self.estimated_equilibrium))\r\n                self.smiths_alpha.append( alpha/self.estimated_equilibrium[-1] )\r\n\r\n        def calcTheta(self):\r\n                gamma = 2.0 #not sensitive apparently so choose to be whatever\r\n                # necessary for intialisation, div by 0\r\n                if min(self.smiths_alpha) == max(self.smiths_alpha):\r\n                        alpha_range = 0.4 #starting value i guess\r\n                else:\r\n                        alpha_range = (self.smiths_alpha[-1] - min(self.smiths_alpha)) / (max(self.smiths_alpha) - min(self.smiths_alpha))\r\n                theta_range = self.theta_max - self.theta_min\r\n                desired_theta = self.theta_min + (theta_range) * (1 - (alpha_range * math.exp(gamma * (alpha_range - 1))))\r\n                self.theta = self.theta + self.long_term_learning_rate * (desired_theta - self.theta)\r\n\r\n        def calcRshout(self):\r\n                p = self.estimated_equilibrium[-1]\r\n                l = self.limit\r\n                theta = self.theta\r\n                if self.job == 'Bid':\r\n                        # Currently a buyer\r\n                        if l <= p: #extramarginal!\r\n                                self.r_shout = 0.0\r\n                        else: #intramarginal :(\r\n                                if self.buy_target > self.estimated_equilibrium[-1]:\r\n                                        #r[0,1]\r\n                                        self.r_shout = math.log(((self.buy_target - p) * (math.exp(theta) - 1) / (l - p)) + 1) / theta\r\n                                else:\r\n                                        #r[-1,0]\r\n                                        self.r_shout = math.log((1 - (self.buy_target/p)) * (math.exp(theta) - 1) + 1) / theta\r\n\r\n\r\n                if self.job == 'Ask':\r\n                        # Currently a seller\r\n                        if l >= p: #extramarginal!\r\n                                self.r_shout = 0\r\n                        else: #intramarginal :(\r\n                                if self.sell_target > self.estimated_equilibrium[-1]:\r\n                                        # r[-1,0]\r\n                                        self.r_shout = math.log((self.sell_target - p) * (math.exp(theta) - 1) / (self.marketMax - p) + 1) / theta\r\n                                else:\r\n                                        # r[0,1]\r\n                                        a = (self.sell_target-l)/(p-l)\r\n                                        self.r_shout = (math.log((1 - a) * (math.exp(theta) - 1) + 1)) / theta\r\n\r\n        def calcAgg(self):\r\n                delta = 0\r\n                if self.job == 'Bid':\r\n                        # BUYER\r\n                        if self.buy_target >= self.previous_transactions[-1] :\r\n                                # must be more aggressive\r\n                                delta = (1+self.r_shout_change_relative)*self.r_shout + self.r_shout_change_absolute\r\n                        else :\r\n                                delta = (1-self.r_shout_change_relative)*self.r_shout - self.r_shout_change_absolute\r\n\r\n                        self.buy_r = self.buy_r + self.short_term_learning_rate * (delta - self.buy_r)\r\n\r\n                if self.job == 'Ask':\r\n                        # SELLER\r\n                        if self.sell_target > self.previous_transactions[-1] :\r\n                                delta = (1+self.r_shout_change_relative)*self.r_shout + self.r_shout_change_absolute\r\n                        else :\r\n                                delta = (1-self.r_shout_change_relative)*self.r_shout - self.r_shout_change_absolute\r\n\r\n                        self.sell_r = self.sell_r + self.short_term_learning_rate * (delta - self.sell_r)\r\n\r\n        def calcTarget(self):\r\n                if len(self.estimated_equilibrium) > 0:\r\n                        p = self.estimated_equilibrium[-1]\r\n                        if self.limit == p:\r\n                                p = p * 1.000001 # to prevent theta_bar = 0\r\n                elif self.job == 'Bid':\r\n                        p = self.limit - self.limit * 0.2  ## Initial guess for eq if no deals yet!!....\r\n                elif self.job == 'Ask':\r\n                        p = self.limit + self.limit * 0.2\r\n                l = self.limit\r\n                theta = self.theta\r\n                if self.job == 'Bid':\r\n                        #BUYER\r\n                        minus_thing = (math.exp(-self.buy_r * theta) - 1) / (math.exp(theta) - 1)\r\n                        plus_thing = (math.exp(self.buy_r * theta) - 1) / (math.exp(theta) - 1)\r\n                        theta_bar = (theta * l - theta * p) / p\r\n                        if theta_bar == 0:\r\n                                theta_bar = 0.0001\r\n                        if math.exp(theta_bar) - 1 == 0:\r\n                                theta_bar = 0.0001\r\n                        bar_thing = (math.exp(-self.buy_r * theta_bar) - 1) / (math.exp(theta_bar) - 1)\r\n                        if l <= p: #Extramarginal\r\n                                if self.buy_r >= 0:\r\n                                        self.buy_target = l\r\n                                else:\r\n                                        self.buy_target = l * (1 - minus_thing)\r\n                        else: #intramarginal\r\n                                if self.buy_r >= 0:\r\n                                        self.buy_target = p + (l-p)*plus_thing\r\n                                else:\r\n                                        self.buy_target = p*(1-bar_thing)\r\n                        if self.buy_target > l:\r\n                                self.buy_target = l\r\n\r\n                if self.job == 'Ask':\r\n                        #SELLER\r\n                        minus_thing = (math.exp(-self.sell_r * theta) - 1) / (math.exp(theta) - 1)\r\n                        plus_thing = (math.exp(self.sell_r * theta) - 1) / (math.exp(theta) - 1)\r\n                        theta_bar = (theta * l - theta * p) / p\r\n                        if theta_bar == 0:\r\n                                theta_bar = 0.0001\r\n                        if math.exp(theta_bar) - 1 == 0:\r\n                                theta_bar = 0.0001\r\n                        bar_thing = (math.exp(-self.sell_r * theta_bar) - 1) / (math.exp(theta_bar) - 1) #div 0 sometimes what!?\r\n                        if l <= p: #Extramarginal\r\n                                if self.buy_r >= 0:\r\n                                        self.buy_target = l\r\n                                else:\r\n                                        self.buy_target = l + (self.marketMax - l)*(minus_thing)\r\n                        else: #intramarginal\r\n                                if self.buy_r >= 0:\r\n                                        self.buy_target = l + (p-l)*(1-plus_thing)\r\n                                else:\r\n                                        self.buy_target = p + (self.marketMax - p)*(bar_thing)\r\n                        if self.sell_target < l:\r\n                                self.sell_target = l\r\n\r\n        def getorder(self, time, countdown, lob):\r\n                if len(self.orders) < 1:\r\n                        self.active = False\r\n                        return None\r\n                else:\r\n                        self.active = True\r\n                        self.limit = self.orders[0].price\r\n                        self.job = self.orders[0].otype\r\n                        self.calcTarget()\r\n\r\n                        if self.prev_best_bid_p == None:\r\n                                o_bid = 0\r\n                        else:\r\n                                o_bid = self.prev_best_bid_p\r\n                        if self.prev_best_ask_p == None:\r\n                                o_ask = self.marketMax\r\n                        else:\r\n                                o_ask = self.prev_best_ask_p\r\n\r\n                        if self.job == 'Bid': #BUYER\r\n                                if self.limit <= o_bid:\r\n                                        return None\r\n                                else:\r\n                                        if len(self.previous_transactions) > 0: ## has been at least one transaction\r\n                                                o_ask_plus = (1+self.r_shout_change_relative)*o_ask + self.r_shout_change_absolute\r\n                                                quoteprice = o_bid + ((min(self.limit, o_ask_plus) - o_bid) / self.offer_change_rate)\r\n                                        else:\r\n                                                if o_ask <= self.buy_target:\r\n                                                        quoteprice = o_ask\r\n                                                else:\r\n                                                        quoteprice = o_bid + ((self.buy_target - o_bid) / self.offer_change_rate)\r\n                        if self.job == 'Ask':\r\n                                if self.limit >= o_ask:\r\n                                        return None\r\n                                else:\r\n                                        if len(self.previous_transactions) > 0: ## has been at least one transaction\r\n                                                o_bid_minus = (1-self.r_shout_change_relative) * o_bid - self.r_shout_change_absolute\r\n                                                quoteprice = o_ask - ((o_ask - max(self.limit, o_bid_minus)) / self.offer_change_rate)\r\n                                        else:\r\n                                                if o_bid >= self.sell_target:\r\n                                                        quoteprice = o_bid\r\n                                                else:\r\n                                                        quoteprice = o_ask - ((o_ask - self.sell_target) / self.offer_change_rate)\r\n\r\n\r\n                        order = Order(self.tid,\r\n                                    self.orders[0].otype,\r\n                                    quoteprice,\r\n                                    self.orders[0].qty,\r\n                                    time, lob['QID'])\r\n                        self.lastquote=order\r\n                return order\r\n\r\n        def respond(self, time, lob, trade, verbose):\r\n            ## Begin nicked from ZIP\r\n\r\n            # what, if anything, has happened on the bid LOB? Nicked from ZIP..\r\n            bid_improved = False\r\n            bid_hit = False\r\n            lob_best_bid_p = lob['bids']['best']\r\n            lob_best_bid_q = None\r\n            if lob_best_bid_p != None:\r\n                    # non-empty bid LOB\r\n                    lob_best_bid_q = lob['bids']['lob'][-1][1]\r\n                    if self.prev_best_bid_p < lob_best_bid_p :\r\n                            # best bid has improved\r\n                            # NB doesn't check if the improvement was by self\r\n                            bid_improved = True\r\n                    elif trade != None and ((self.prev_best_bid_p > lob_best_bid_p) or ((self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\r\n                            # previous best bid was hit\r\n                            bid_hit = True\r\n            elif self.prev_best_bid_p != None:\r\n                    # the bid LOB has been emptied: was it cancelled or hit?\r\n                    last_tape_item = lob['tape'][-1]\r\n                    if last_tape_item['type'] == 'Cancel' :\r\n                            bid_hit = False\r\n                    else:\r\n                            bid_hit = True\r\n\r\n            # what, if anything, has happened on the ask LOB?\r\n            ask_improved = False\r\n            ask_lifted = False\r\n            lob_best_ask_p = lob['asks']['best']\r\n            lob_best_ask_q = None\r\n            if lob_best_ask_p != None:\r\n                    # non-empty ask LOB\r\n                    lob_best_ask_q = lob['asks']['lob'][0][1]\r\n                    if self.prev_best_ask_p > lob_best_ask_p :\r\n                            # best ask has improved -- NB doesn't check if the improvement was by self\r\n                            ask_improved = True\r\n                    elif trade != None and ((self.prev_best_ask_p < lob_best_ask_p) or ((self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\r\n                            # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\r\n                            ask_lifted = True\r\n            elif self.prev_best_ask_p != None:\r\n                    # the ask LOB is empty now but was not previously: canceled or lifted?\r\n                    last_tape_item = lob['tape'][-1]\r\n                    if last_tape_item['type'] == 'Cancel' :\r\n                            ask_lifted = False\r\n                    else:\r\n                            ask_lifted = True\r\n\r\n            self.prev_best_bid_p = lob_best_bid_p\r\n            self.prev_best_bid_q = lob_best_bid_q\r\n            self.prev_best_ask_p = lob_best_ask_p\r\n            self.prev_best_ask_q = lob_best_ask_q\r\n\r\n            deal = bid_hit or ask_lifted\r\n\r\n            ## End nicked from ZIP\r\n\r\n            if deal:\r\n                    self.previous_transactions.append(trade['price'])\r\n                    if self.sell_target == None:\r\n                            self.sell_target = trade['price']\r\n                    if self.buy_target == None:\r\n                            self.buy_target = trade['price']\r\n                    self.calcEq()\r\n                    self.calcAlpha()\r\n                    self.calcTheta()\r\n                    self.calcRshout()\r\n                    self.calcAgg()\r\n                    self.calcTarget()\r\n                    #print 'sell: ', self.sell_target, 'buy: ', self.buy_target, 'limit:', self.limit, 'eq: ',  self.estimated_equilibrium[-1], 'sell_r: ', self.sell_r, 'buy_r: ', self.buy_r, '\\n'\r\n\r\n\r\n\r\n# Trader subclass ZI-C\r\n# After Gode & Sunder 1993\r\nclass Trader_ZIC(Trader):\r\n\r\n        def getorder(self, time, countdown, lob):\r\n                if len(self.orders) < 1:\r\n                        # no orders: return NULL\r\n                        order = None\r\n                else:\r\n                        minprice = lob['bids']['worst']\r\n                        maxprice = lob['asks']['worst']\r\n                        qid = lob['QID']\r\n                        limit = self.orders[0].price\r\n                        otype = self.orders[0].otype\r\n                        if otype == 'Bid':\r\n                                quoteprice = random.randint(minprice, limit)\r\n                        else:\r\n                                quoteprice = random.randint(limit, maxprice)\r\n                                # NB should check it == 'Ask' and barf if not\r\n                        order = Order(self.tid, otype, quoteprice, self.orders[0].qty, time, qid)\r\n                        self.lastquote = order\r\n                return order\r\n\r\n\r\n# Trader subclass Shaver\r\n# shaves a penny off the best price\r\n# if there is no best price, creates \"stub quote\" at system max/min\r\nclass Trader_Shaver(Trader):\r\n\r\n        def getorder(self, time, countdown, lob):\r\n                if len(self.orders) < 1:\r\n                        order = None\r\n                else:\r\n                        limitprice = self.orders[0].price\r\n                        otype = self.orders[0].otype\r\n                        if otype == 'Bid':\r\n                                if lob['bids']['n'] > 0:\r\n                                        quoteprice = lob['bids']['best'] + 1\r\n                                        if quoteprice > limitprice :\r\n                                                quoteprice = limitprice\r\n                                else:\r\n                                        quoteprice = lob['bids']['worst']\r\n                        else:\r\n                                if lob['asks']['n'] > 0:\r\n                                        quoteprice = lob['asks']['best'] - 1\r\n                                        if quoteprice < limitprice:\r\n                                                quoteprice = limitprice\r\n                                else:\r\n                                        quoteprice = lob['asks']['worst']\r\n                        order = Order(self.tid, otype, quoteprice, self.orders[0].qty, time, lob['QID'])\r\n                        self.lastquote = order\r\n                return order\r\n\r\n\r\n# Trader subclass Sniper\r\n# Based on Shaver,\r\n# \"lurks\" until time remaining < threshold% of the trading session\r\n# then gets increasing aggressive, increasing \"shave thickness\" as time runs out\r\nclass Trader_Sniper(Trader):\r\n\r\n        def getorder(self, time, countdown, lob):\r\n                lurk_threshold = 0.2\r\n                shavegrowthrate = 3\r\n                shave = int(1.0 / (0.01 + countdown / (shavegrowthrate * lurk_threshold)))\r\n                if (len(self.orders) < 1) or (countdown > lurk_threshold):\r\n                        order = None\r\n                else:\r\n                        limitprice = self.orders[0].price\r\n                        otype = self.orders[0].otype\r\n\r\n                        if otype == 'Bid':\r\n                                if lob['bids']['n'] > 0:\r\n                                        quoteprice = lob['bids']['best'] + shave\r\n                                        if quoteprice > limitprice :\r\n                                                quoteprice = limitprice\r\n                                else:\r\n                                        quoteprice = lob['bids']['worst']\r\n                        else:\r\n                                if lob['asks']['n'] > 0:\r\n                                        quoteprice = lob['asks']['best'] - shave\r\n                                        if quoteprice < limitprice:\r\n                                                quoteprice = limitprice\r\n                                else:\r\n                                        quoteprice = lob['asks']['worst']\r\n                        order = Order(self.tid, otype, quoteprice, self.orders[0].qty, time, lob['QID'])\r\n                        self.lastquote = order\r\n                return order\r\n\r\n\r\n\r\n\r\n# Trader subclass ZIP\r\n# After Cliff 1997\r\nclass Trader_ASAD(Trader):\r\n\r\n        # ZIP init key param-values are those used in Cliff's 1997 original HP Labs tech report\r\n        # NB this implementation keeps separate margin values for buying & selling,\r\n        #    so a single trader can both buy AND sell\r\n        #    -- in the original, traders were either buyers OR sellers\r\n\r\n        def __init__(self, ttype, tid, balance, time):\r\n                self.ttype = ttype\r\n                self.tid = tid\r\n                self.balance = balance\r\n                self.birthtime = time\r\n                self.profitpertime = 0\r\n                self.n_trades = 0\r\n                self.blotter = []\r\n                self.orders = []\r\n                self.prev_orders = []\r\n                self.n_quotes = 0\r\n                self.lastquote = None\r\n                self.job = None  # this gets switched to 'Bid' or 'Ask' depending on order-type\r\n                self.active = False  # gets switched to True while actively working an order\r\n                self.prev_change = 0  # this was called last_d in Cliff'97\r\n                self.beta = 0.1 + 0.4 * random.random()\r\n                self.momntm = 0.1 * random.random()\r\n                self.ca = 0.05  # self.ca & .cr were hard-coded in '97 but parameterised later\r\n                self.cr = 0.05\r\n                self.margin = None  # this was called profit in Cliff'97\r\n                self.margin_buy = -1.0 * (0.05 + 0.3 * random.random())\r\n                self.margin_sell = 0.05 + 0.3 * random.random()\r\n                self.price = None\r\n                self.limit = None\r\n                self.phi = 0 #measure of market shock for ASAD\r\n                # memory of best price & quantity of best bid and ask, on LOB on previous update\r\n                self.prev_best_bid_p = None\r\n                self.prev_best_bid_q = None\r\n                self.prev_best_ask_p = None\r\n                self.prev_best_ask_q = None\r\n\r\n\r\n        def getorder(self, time, countdown, lob):\r\n                if len(self.orders) < 1:\r\n                        self.active = False\r\n                        order = None\r\n                else:\r\n                        self.active = True\r\n                        self.limit = self.orders[0].price\r\n                        self.job = self.orders[0].otype\r\n                        if self.job == 'Bid':\r\n                                # currently a buyer (working a bid order)\r\n                                self.margin = self.margin_buy\r\n                        else:\r\n                                # currently a seller (working a sell order)\r\n                                self.margin = self.margin_sell\r\n                        quoteprice = int(self.limit * (1 + self.margin))\r\n                        self.price = quoteprice\r\n\r\n                        order = Order(self.tid, self.job, quoteprice, self.orders[0].qty, time, lob['QID'])\r\n                        self.lastquote = order\r\n                        self.prev_orders.append(order)\r\n                return order\r\n\r\n\r\n        # update margin on basis of what happened in market\r\n        def respond(self, time, lob, trade, verbose):\r\n                # ZIP trader responds to market events, altering its margin\r\n                # does this whether it currently has an order to work or not\r\n\r\n                def target_up(price):\r\n                        # generate a higher target price by randomly perturbing given price\r\n                        ptrb_abs = self.ca * random.random()  # absolute shift\r\n                        ptrb_rel = price * (1.0 + (self.cr * random.random()))  # relative shift\r\n                        target = int(round(ptrb_rel + ptrb_abs, 0))\r\n# #                        print('TargetUp: %d %d\\n' % (price,target))\r\n                        return(target)\r\n\r\n\r\n                def target_down(price):\r\n                        # generate a lower target price by randomly perturbing given price\r\n                        ptrb_abs = self.ca * random.random()  # absolute shift\r\n                        ptrb_rel = price * (1.0 - (self.cr * random.random()))  # relative shift\r\n                        target = int(round(ptrb_rel - ptrb_abs, 0))\r\n# #                        print('TargetDn: %d %d\\n' % (price,target))\r\n                        return(target)\r\n\r\n\r\n                def willing_to_trade(price):\r\n                        # am I willing to trade at this price?\r\n                        willing = False\r\n                        if self.job == 'Bid' and self.active and self.price >= price:\r\n                                willing = True\r\n                        if self.job == 'Ask' and self.active and self.price <= price:\r\n                                willing = True\r\n                        return willing\r\n\r\n\r\n                def profit_alter(price):\r\n                        oldprice = self.price\r\n                        diff = price - oldprice\r\n                        change = ((1.0 - self.momntm) * (self.beta * diff)) + (self.momntm * self.prev_change)\r\n                        self.prev_change = change\r\n                        newmargin = ((self.price + change) / self.limit) - 1.0\r\n\r\n                        if self.job == 'Bid':\r\n                                if newmargin < 0.0 :\r\n                                        self.margin_buy = newmargin\r\n                                        self.margin = newmargin\r\n                        else :\r\n                                if newmargin > 0.0 :\r\n                                        self.margin_sell = newmargin\r\n                                        self.margin = newmargin\r\n\r\n                        # set the price from limit and profit-margin\r\n                        self.price = int(round(self.limit * (1.0 + self.margin), 0))\r\n# #                        print('old=%d diff=%d change=%d price = %d\\n' % (oldprice, diff, change, self.price))\r\n\r\n                def calc_phi():\r\n                        if len(self.prev_orders) < 20:\r\n                                return\r\n                        sumxy = 0\r\n                        sumx = 0\r\n                        sumxsq = 0\r\n                        sumy = 0\r\n                        for i in range(20):\r\n                                sumxy = sumxy + i * self.prev_orders[-20:][i].price\r\n                                sumx =  sumx + i\r\n                                sumxsq = sumxsq + i*i\r\n                                sumy = sumy + self.prev_orders[-20:][i].price\r\n                        delta = (sumxy - (sumy * sumx / 20)) / (sumxsq - (sumx * sumx / 20))\r\n                        if delta < 0:\r\n                                self.phi = -math.log(1-delta)\r\n                        else:\r\n                                self.phi = math.log(1+delta)\r\n\r\n                # what, if anything, has happened on the bid LOB?\r\n                bid_improved = False\r\n                bid_hit = False\r\n                lob_best_bid_p = lob['bids']['best']\r\n                lob_best_bid_q = None\r\n                if lob_best_bid_p != None:\r\n                        # non-empty bid LOB\r\n                        lob_best_bid_q = lob['bids']['lob'][-1][1]\r\n                        if self.prev_best_bid_p < lob_best_bid_p :\r\n                                # best bid has improved\r\n                                # NB doesn't check if the improvement was by self\r\n                                bid_improved = True\r\n                        elif trade != None and ((self.prev_best_bid_p > lob_best_bid_p) or ((self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\r\n                                # previous best bid was hit\r\n                                bid_hit = True\r\n                elif self.prev_best_bid_p != None:\r\n                        # the bid LOB has been emptied: was it cancelled or hit?\r\n                        last_tape_item = lob['tape'][-1]\r\n                        if last_tape_item['type'] == 'Cancel' :\r\n                                bid_hit = False\r\n                        else:\r\n                                bid_hit = True\r\n\r\n                # what, if anything, has happened on the ask LOB?\r\n                ask_improved = False\r\n                ask_lifted = False\r\n                lob_best_ask_p = lob['asks']['best']\r\n                lob_best_ask_q = None\r\n                if lob_best_ask_p != None:\r\n                        # non-empty ask LOB\r\n                        lob_best_ask_q = lob['asks']['lob'][0][1]\r\n                        if self.prev_best_ask_p > lob_best_ask_p :\r\n                                # best ask has improved -- NB doesn't check if the improvement was by self\r\n                                ask_improved = True\r\n                        elif trade != None and ((self.prev_best_ask_p < lob_best_ask_p) or ((self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\r\n                                # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\r\n                                ask_lifted = True\r\n                elif self.prev_best_ask_p != None:\r\n                        # the ask LOB is empty now but was not previously: canceled or lifted?\r\n                        last_tape_item = lob['tape'][-1]\r\n                        if last_tape_item['type'] == 'Cancel' :\r\n                                ask_lifted = False\r\n                        else:\r\n                                ask_lifted = True\r\n\r\n\r\n                if verbose and (bid_improved or bid_hit or ask_improved or ask_lifted):\r\n                        print ('B_improved', bid_improved, 'B_hit', bid_hit, 'A_improved', ask_improved, 'A_lifted', ask_lifted)\r\n\r\n\r\n                deal = bid_hit or ask_lifted\r\n\r\n                calc_phi()\r\n\r\n\r\n                if self.job == 'Ask':\r\n                        # seller\r\n                        if deal :\r\n                                tradeprice = trade['price']\r\n                                if self.price <= tradeprice:\r\n                                        # could sell for more? raise margin\r\n                                        target_price = target_up(tradeprice)\r\n                                        if self.phi > 1:\r\n                                                target_price = target_up(target_price)\r\n                                        profit_alter(target_price)\r\n                                elif ask_lifted and self.active and not willing_to_trade(tradeprice):\r\n                                        # wouldnt have got this deal, still working order, so reduce margin\r\n                                        target_price = target_down(tradeprice)\r\n                                        if self.phi > 1:\r\n                                                target_price = target_up(target_price)\r\n                                        profit_alter(target_price)\r\n                        else:\r\n                                # no deal: aim for a target price higher than best bid\r\n                                if ask_improved and self.price > lob_best_ask_p:\r\n                                        if lob_best_bid_p != None:\r\n                                                target_price = target_up(lob_best_bid_p)\r\n                                        else:\r\n                                                target_price = lob['asks']['worst']  # stub quote\r\n                                        profit_alter(target_price)\r\n\r\n                if self.job == 'Bid':\r\n                        # buyer\r\n                        if deal :\r\n                                tradeprice = trade['price']\r\n                                if self.price >= tradeprice:\r\n                                        # could buy for less? raise margin (i.e. cut the price)\r\n                                        target_price = target_down(tradeprice)\r\n                                        if self.phi < -1:\r\n                                                target_price = target_up(target_price)\r\n                                        profit_alter(target_price)\r\n                                elif bid_hit and self.active and not willing_to_trade(tradeprice):\r\n                                        # wouldnt have got this deal, still working order, so reduce margin\r\n                                        target_price = target_up(tradeprice)\r\n                                        if self.phi < -1:\r\n                                                target_price = target_up(target_price)\r\n                                        profit_alter(target_price)\r\n                        else:\r\n                                # no deal: aim for target price lower than best ask\r\n                                if bid_improved and self.price < lob_best_bid_p:\r\n                                        if lob_best_ask_p != None:\r\n                                                target_price = target_down(lob_best_ask_p)\r\n                                        else:\r\n                                                target_price = lob['bids']['worst']  # stub quote\r\n                                        profit_alter(target_price)\r\n\r\n\r\n                # remember the best LOB data ready for next response\r\n                self.prev_best_bid_p = lob_best_bid_p\r\n                self.prev_best_bid_q = lob_best_bid_q\r\n                self.prev_best_ask_p = lob_best_ask_p\r\n                self.prev_best_ask_q = lob_best_ask_q\r\n\r\n\r\n# Trader subclass ZIP\r\n# After Cliff 1997\r\nclass Trader_GDX(Trader):\r\n\r\n        def __init__(self, ttype, tid, balance, time):\r\n                self.ttype = ttype\r\n                self.tid = tid\r\n                self.balance = balance\r\n                self.birthtime = time\r\n                self.profitpertime = 0\r\n                self.n_trades = 0\r\n                self.blotter = []\r\n                self.orders = []\r\n                self.prev_orders = []\r\n                self.n_quotes = 0\r\n                self.lastquote = None\r\n                self.job = None  # this gets switched to 'Bid' or 'Ask' depending on order-type\r\n                self.active = False  # gets switched to True while actively working an order\r\n\r\n                #memory of all bids and asks and accepted bids and asks\r\n                self.outstanding_bids = []\r\n                self.outstanding_asks = []\r\n                self.accepted_asks = []\r\n                self.accepted_bids = []\r\n\r\n                self.price = -1\r\n\r\n                # memory of best price & quantity of best bid and ask, on LOB on previous update\r\n                self.prev_best_bid_p = None\r\n                self.prev_best_bid_q = None\r\n                self.prev_best_ask_p = None\r\n                self.prev_best_ask_q = None\r\n\r\n                self.first_turn = True\r\n\r\n                self.gamma = 0.1\r\n\r\n                self.holdings = 10\r\n                self.remaining_offer_ops = 10\r\n                self.values = [[0 for n in range(self.remaining_offer_ops)] for m in range(self.holdings)]\r\n\r\n\r\n        def getorder(self, time, countdown, lob):\r\n                if len(self.orders) < 1:\r\n                        self.active = False\r\n                        order = None\r\n                else:\r\n                        self.active = True\r\n                        self.limit = self.orders[0].price\r\n                        self.job = self.orders[0].otype\r\n\r\n                        #calculate price\r\n                        if self.job == 'Bid':\r\n                                self.price = self.calc_p_bid(self.holdings - 1, self.remaining_offer_ops - 1)\r\n                        if self.job == 'Ask':\r\n                                self.price = self.calc_p_ask(self.holdings - 1, self.remaining_offer_ops - 1)\r\n\r\n                        order = Order(self.tid, self.job, self.price, self.orders[0].qty, time, lob['QID'])\r\n                        self.lastquote = order\r\n\r\n                if self.first_turn or self.price == -1:\r\n                        return None\r\n                return order\r\n\r\n        def calc_p_bid(self, m, n):\r\n                best_return = 0\r\n                best_bid = 0\r\n                second_best_return = 0\r\n                second_best_bid = 0\r\n\r\n                #first step size of 1 get best and 2nd best\r\n                for i in [x*2 for x in range(int(self.limit/2))]:\r\n                        thing = self.belief_buy(i) * ((self.limit - i) + self.gamma*self.values[m-1][n-1]) + (1-self.belief_buy(i) * self.gamma * self.values[m][n-1])\r\n                        if thing > best_return:\r\n                                second_best_bid = best_bid\r\n                                second_best_return = best_return\r\n                                best_return = thing\r\n                                best_bid = i\r\n\r\n                #always best bid largest one\r\n                if second_best_bid > best_bid:\r\n                        a = second_best_bid\r\n                        second_best_bid = best_bid\r\n                        best_bid = a\r\n\r\n                #then step size 0.05\r\n                for i in [x*0.05 for x in range(int(second_best_bid), int(best_bid))]:\r\n                        thing = self.belief_buy(i + second_best_bid) * ((self.limit - (i + second_best_bid)) + self.gamma*self.values[m-1][n-1]) + (1-self.belief_buy(i + second_best_bid) * self.gamma * self.values[m][n-1])\r\n                        if thing > best_return:\r\n                                best_return = thing\r\n                                best_bid = i + second_best_bid\r\n\r\n                return best_bid\r\n\r\n        def calc_p_ask(self, m, n):\r\n                best_return = 0\r\n                best_ask = self.limit\r\n                second_best_return = 0\r\n                second_best_ask = self.limit\r\n\r\n                #first step size of 1 get best and 2nd best\r\n                for i in [x*2 for x in range(int(self.limit/2))]:\r\n                        j = i + self.limit\r\n                        thing =  self.belief_sell(j) * ((j - self.limit) + self.gamma*self.values[m-1][n-1]) + (1-self.belief_sell(j) * self.gamma * self.values[m][n-1])\r\n                        if thing > best_return:\r\n                                second_best_ask = best_ask\r\n                                second_best_return = best_return\r\n                                best_return = thing\r\n                                best_ask = j\r\n                #always best ask largest one\r\n                if second_best_ask > best_ask:\r\n                        a = second_best_ask\r\n                        second_best_ask = best_ask\r\n                        best_ask = a\r\n\r\n                #then step size 0.05\r\n                for i in [x*0.05 for x in range(int(second_best_ask), int(best_ask))]:\r\n                        thing = self.belief_sell(i + second_best_ask) * (((i + second_best_ask) - self.limit) + self.gamma*self.values[m-1][n-1]) + (1-self.belief_sell(i + second_best_ask) * self.gamma * self.values[m][n-1])\r\n                        if thing > best_return:\r\n                                best_return = thing\r\n                                best_ask = i + second_best_ask\r\n\r\n                return best_ask\r\n\r\n        def belief_sell(self, price):\r\n                accepted_asks_greater = 0\r\n                bids_greater = 0\r\n                unaccepted_asks_lower = 0\r\n                for p in self.accepted_asks:\r\n                        if p >= price:\r\n                                accepted_asks_greater += 1\r\n                for p in [thing[0] for thing in self.outstanding_bids]:\r\n                        if p >= price:\r\n                                bids_greater += 1\r\n                for p in [thing[0] for thing in self.outstanding_asks]:\r\n                        if p <= price:\r\n                                unaccepted_asks_lower += 1\r\n\r\n                if accepted_asks_greater + bids_greater + unaccepted_asks_lower == 0:\r\n                        return 0\r\n                return (accepted_asks_greater + bids_greater) / (accepted_asks_greater + bids_greater + unaccepted_asks_lower)\r\n\r\n        def belief_buy(self, price):\r\n                accepted_bids_lower = 0\r\n                asks_lower = 0\r\n                unaccepted_bids_greater = 0\r\n                for p in self.accepted_bids:\r\n                        if p <= price:\r\n                                accepted_bids_lower += 1\r\n                for p in [thing[0] for thing in self.outstanding_asks]:\r\n                        if p <= price:\r\n                                asks_lower += 1\r\n                for p in [thing[0] for thing in self.outstanding_bids]:\r\n                        if p >= price:\r\n                                unaccepted_bids_greater += 1\r\n                if accepted_bids_lower + asks_lower + unaccepted_bids_greater == 0:\r\n                        return 0\r\n                return (accepted_bids_lower + asks_lower) / (accepted_bids_lower + asks_lower + unaccepted_bids_greater)\r\n\r\n        def respond(self, time, lob, trade, verbose):\r\n                # what, if anything, has happened on the bid LOB?\r\n                self.outstanding_bids = lob['bids']['lob']\r\n                bid_improved = False\r\n                bid_hit = False\r\n                lob_best_bid_p = lob['bids']['best']\r\n                lob_best_bid_q = None\r\n                if lob_best_bid_p != None:\r\n                        # non-empty bid LOB\r\n                        lob_best_bid_q = lob['bids']['lob'][-1][1]\r\n                        if self.prev_best_bid_p < lob_best_bid_p :\r\n                                # best bid has improved\r\n                                # NB doesn't check if the improvement was by self\r\n                                bid_improved = True\r\n                        elif trade != None and ((self.prev_best_bid_p > lob_best_bid_p) or ((self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\r\n                                # previous best bid was hit\r\n                                self.accepted_bids.append(self.prev_best_bid_p)\r\n                                bid_hit = True\r\n                elif self.prev_best_bid_p != None:\r\n                        # the bid LOB has been emptied: was it cancelled or hit?\r\n                        last_tape_item = lob['tape'][-1]\r\n                        if last_tape_item['type'] == 'Cancel' :\r\n                                bid_hit = False\r\n                        else:\r\n                                bid_hit = True\r\n\r\n                # what, if anything, has happened on the ask LOB?\r\n                self.outstanding_asks = lob['asks']['lob']\r\n                ask_improved = False\r\n                ask_lifted = False\r\n                lob_best_ask_p = lob['asks']['best']\r\n                lob_best_ask_q = None\r\n                if lob_best_ask_p != None:\r\n                        # non-empty ask LOB\r\n                        lob_best_ask_q = lob['asks']['lob'][0][1]\r\n                        if self.prev_best_ask_p > lob_best_ask_p :\r\n                                # best ask has improved -- NB doesn't check if the improvement was by self\r\n                                ask_improved = True\r\n                        elif trade != None and ((self.prev_best_ask_p < lob_best_ask_p) or ((self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\r\n                                # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\r\n                                self.accepted_asks.append(self.prev_best_ask_p)\r\n                                ask_lifted = True\r\n                elif self.prev_best_ask_p != None:\r\n                        # the ask LOB is empty now but was not previously: canceled or lifted?\r\n                        last_tape_item = lob['tape'][-1]\r\n                        if last_tape_item['type'] == 'Cancel' :\r\n                                ask_lifted = False\r\n                        else:\r\n                                ask_lifted = True\r\n\r\n\r\n                #populate expected values\r\n                if self.first_turn:\r\n                        print \"populating\"\r\n                        self.first_turn = False\r\n                        for n in range(1, self.remaining_offer_ops):\r\n                                for m in range(1, self.holdings):\r\n                                            if self.job == 'Bid':\r\n                                                    #BUYER\r\n                                                    self.values[m][n] = self.calc_p_bid(m, n)\r\n\r\n                                            if self.job == 'Ask':\r\n                                                    #BUYER\r\n                                                    self.values[m][n] = self.calc_p_ask(m, n)\r\n                        print \"done\"\r\n\r\n\r\n                deal = bid_hit or ask_lifted\r\n\r\n\r\n                # remember the best LOB data ready for next response\r\n                self.prev_best_bid_p = lob_best_bid_p\r\n                self.prev_best_bid_q = lob_best_bid_q\r\n                self.prev_best_ask_p = lob_best_ask_p\r\n                self.prev_best_ask_q = lob_best_ask_q\r\n\r\n\r\n\r\n\r\n# Trader subclass ZIP\r\n# After Cliff 1997\r\nclass Trader_ZIP(Trader):\r\n\r\n        # ZIP init key param-values are those used in Cliff's 1997 original HP Labs tech report\r\n        # NB this implementation keeps separate margin values for buying & selling,\r\n        #    so a single trader can both buy AND sell\r\n        #    -- in the original, traders were either buyers OR sellers\r\n\r\n        def __init__(self, ttype, tid, balance, time):\r\n                self.ttype = ttype\r\n                self.tid = tid\r\n                self.balance = balance\r\n                self.birthtime = time\r\n                self.profitpertime = 0\r\n                self.n_trades = 0\r\n                self.blotter = []\r\n                self.orders = []\r\n                self.n_quotes = 0\r\n                self.lastquote = None\r\n                self.job = None  # this gets switched to 'Bid' or 'Ask' depending on order-type\r\n                self.active = False  # gets switched to True while actively working an order\r\n                self.prev_change = 0  # this was called last_d in Cliff'97\r\n                self.beta = 0.1 + 0.4 * random.random()\r\n                self.momntm = 0.1 * random.random()\r\n                self.ca = 0.05  # self.ca & .cr were hard-coded in '97 but parameterised later\r\n                self.cr = 0.05\r\n                self.margin = None  # this was called profit in Cliff'97\r\n                self.margin_buy = -1.0 * (0.05 + 0.3 * random.random())\r\n                self.margin_sell = 0.05 + 0.3 * random.random()\r\n                self.price = None\r\n                self.limit = None\r\n                # memory of best price & quantity of best bid and ask, on LOB on previous update\r\n                self.prev_best_bid_p = None\r\n                self.prev_best_bid_q = None\r\n                self.prev_best_ask_p = None\r\n                self.prev_best_ask_q = None\r\n\r\n\r\n        def getorder(self, time, countdown, lob):\r\n                if len(self.orders) < 1:\r\n                        self.active = False\r\n                        order = None\r\n                else:\r\n                        self.active = True\r\n                        self.limit = self.orders[0].price\r\n                        self.job = self.orders[0].otype\r\n                        if self.job == 'Bid':\r\n                                # currently a buyer (working a bid order)\r\n                                self.margin = self.margin_buy\r\n                        else:\r\n                                # currently a seller (working a sell order)\r\n                                self.margin = self.margin_sell\r\n                        quoteprice = int(self.limit * (1 + self.margin))\r\n                        self.price = quoteprice\r\n\r\n                        order = Order(self.tid, self.job, quoteprice, self.orders[0].qty, time, lob['QID'])\r\n                        self.lastquote = order\r\n                return order\r\n\r\n\r\n        # update margin on basis of what happened in market\r\n        def respond(self, time, lob, trade, verbose):\r\n                # ZIP trader responds to market events, altering its margin\r\n                # does this whether it currently has an order to work or not\r\n\r\n                def target_up(price):\r\n                        # generate a higher target price by randomly perturbing given price\r\n                        ptrb_abs = self.ca * random.random()  # absolute shift\r\n                        ptrb_rel = price * (1.0 + (self.cr * random.random()))  # relative shift\r\n                        target = int(round(ptrb_rel + ptrb_abs, 0))\r\n# #                        print('TargetUp: %d %d\\n' % (price,target))\r\n                        return(target)\r\n\r\n\r\n                def target_down(price):\r\n                        # generate a lower target price by randomly perturbing given price\r\n                        ptrb_abs = self.ca * random.random()  # absolute shift\r\n                        ptrb_rel = price * (1.0 - (self.cr * random.random()))  # relative shift\r\n                        target = int(round(ptrb_rel - ptrb_abs, 0))\r\n# #                        print('TargetDn: %d %d\\n' % (price,target))\r\n                        return(target)\r\n\r\n\r\n                def willing_to_trade(price):\r\n                        # am I willing to trade at this price?\r\n                        willing = False\r\n                        if self.job == 'Bid' and self.active and self.price >= price:\r\n                                willing = True\r\n                        if self.job == 'Ask' and self.active and self.price <= price:\r\n                                willing = True\r\n                        return willing\r\n\r\n\r\n                def profit_alter(price):\r\n                        oldprice = self.price\r\n                        diff = price - oldprice\r\n                        change = ((1.0 - self.momntm) * (self.beta * diff)) + (self.momntm * self.prev_change)\r\n                        self.prev_change = change\r\n                        newmargin = ((self.price + change) / self.limit) - 1.0\r\n\r\n                        if self.job == 'Bid':\r\n                                if newmargin < 0.0 :\r\n                                        self.margin_buy = newmargin\r\n                                        self.margin = newmargin\r\n                        else :\r\n                                if newmargin > 0.0 :\r\n                                        self.margin_sell = newmargin\r\n                                        self.margin = newmargin\r\n\r\n                        # set the price from limit and profit-margin\r\n                        self.price = int(round(self.limit * (1.0 + self.margin), 0))\r\n# #                        print('old=%d diff=%d change=%d price = %d\\n' % (oldprice, diff, change, self.price))\r\n\r\n\r\n                # what, if anything, has happened on the bid LOB?\r\n                bid_improved = False\r\n                bid_hit = False\r\n                lob_best_bid_p = lob['bids']['best']\r\n                lob_best_bid_q = None\r\n                if lob_best_bid_p != None:\r\n                        # non-empty bid LOB\r\n                        lob_best_bid_q = lob['bids']['lob'][-1][1]\r\n                        if self.prev_best_bid_p < lob_best_bid_p :\r\n                                # best bid has improved\r\n                                # NB doesn't check if the improvement was by self\r\n                                bid_improved = True\r\n                        elif trade != None and ((self.prev_best_bid_p > lob_best_bid_p) or ((self.prev_best_bid_p == lob_best_bid_p) and (self.prev_best_bid_q > lob_best_bid_q))):\r\n                                # previous best bid was hit\r\n                                bid_hit = True\r\n                elif self.prev_best_bid_p != None:\r\n                        # the bid LOB has been emptied: was it cancelled or hit?\r\n                        last_tape_item = lob['tape'][-1]\r\n                        if last_tape_item['type'] == 'Cancel' :\r\n                                bid_hit = False\r\n                        else:\r\n                                bid_hit = True\r\n\r\n                # what, if anything, has happened on the ask LOB?\r\n                ask_improved = False\r\n                ask_lifted = False\r\n                lob_best_ask_p = lob['asks']['best']\r\n                lob_best_ask_q = None\r\n                if lob_best_ask_p != None:\r\n                        # non-empty ask LOB\r\n                        lob_best_ask_q = lob['asks']['lob'][0][1]\r\n                        if self.prev_best_ask_p > lob_best_ask_p :\r\n                                # best ask has improved -- NB doesn't check if the improvement was by self\r\n                                ask_improved = True\r\n                        elif trade != None and ((self.prev_best_ask_p < lob_best_ask_p) or ((self.prev_best_ask_p == lob_best_ask_p) and (self.prev_best_ask_q > lob_best_ask_q))):\r\n                                # trade happened and best ask price has got worse, or stayed same but quantity reduced -- assume previous best ask was lifted\r\n                                ask_lifted = True\r\n                elif self.prev_best_ask_p != None:\r\n                        # the ask LOB is empty now but was not previously: canceled or lifted?\r\n                        last_tape_item = lob['tape'][-1]\r\n                        if last_tape_item['type'] == 'Cancel' :\r\n                                ask_lifted = False\r\n                        else:\r\n                                ask_lifted = True\r\n\r\n\r\n                if verbose and (bid_improved or bid_hit or ask_improved or ask_lifted):\r\n                        print ('B_improved', bid_improved, 'B_hit', bid_hit, 'A_improved', ask_improved, 'A_lifted', ask_lifted)\r\n\r\n\r\n                deal = bid_hit or ask_lifted\r\n\r\n                if self.job == 'Ask':\r\n                        # seller\r\n                        if deal :\r\n                                tradeprice = trade['price']\r\n                                if self.price <= tradeprice:\r\n                                        # could sell for more? raise margin\r\n                                        target_price = target_up(tradeprice)\r\n                                        profit_alter(target_price)\r\n                                elif ask_lifted and self.active and not willing_to_trade(tradeprice):\r\n                                        # wouldnt have got this deal, still working order, so reduce margin\r\n                                        target_price = target_down(tradeprice)\r\n                                        profit_alter(target_price)\r\n                        else:\r\n                                # no deal: aim for a target price higher than best bid\r\n                                if ask_improved and self.price > lob_best_ask_p:\r\n                                        if lob_best_bid_p != None:\r\n                                                target_price = target_up(lob_best_bid_p)\r\n                                        else:\r\n                                                target_price = lob['asks']['worst']  # stub quote\r\n                                        profit_alter(target_price)\r\n\r\n                if self.job == 'Bid':\r\n                        # buyer\r\n                        if deal :\r\n                                tradeprice = trade['price']\r\n                                if self.price >= tradeprice:\r\n                                        # could buy for less? raise margin (i.e. cut the price)\r\n                                        target_price = target_down(tradeprice)\r\n                                        profit_alter(target_price)\r\n                                elif bid_hit and self.active and not willing_to_trade(tradeprice):\r\n                                        # wouldnt have got this deal, still working order, so reduce margin\r\n                                        target_price = target_up(tradeprice)\r\n                                        profit_alter(target_price)\r\n                        else:\r\n                                # no deal: aim for target price lower than best ask\r\n                                if bid_improved and self.price < lob_best_bid_p:\r\n                                        if lob_best_ask_p != None:\r\n                                                target_price = target_down(lob_best_ask_p)\r\n                                        else:\r\n                                                target_price = lob['bids']['worst']  # stub quote\r\n                                        profit_alter(target_price)\r\n\r\n\r\n                # remember the best LOB data ready for next response\r\n                self.prev_best_bid_p = lob_best_bid_p\r\n                self.prev_best_bid_q = lob_best_bid_q\r\n                self.prev_best_ask_p = lob_best_ask_p\r\n                self.prev_best_ask_q = lob_best_ask_q\r\n\r\n\r\n\r\n\r\n##########################---trader-types have all been defined now--################\r\n\r\n\r\n\r\n\r\n##########################---Below lies the experiment/test-rig---##################\r\n\r\n\r\n\r\n# trade_stats()\r\n# dump CSV statistics on exchange data and trader population to file for later analysis\r\n# this makes no assumptions about the number of types of traders, or\r\n# the number of traders of any one type -- allows either/both to change\r\n# between successive calls, but that does make it inefficient as it has to\r\n# re-analyse the entire set of traders on each call\r\ndef trade_stats(expid, traders, dumpfile, time, lob):\r\n        trader_types = {}\r\n        n_traders = len(traders)\r\n        for t in traders:\r\n                ttype = traders[t].ttype\r\n                if ttype in trader_types.keys():\r\n                        t_balance = trader_types[ttype]['balance_sum'] + traders[t].balance\r\n                        n = trader_types[ttype]['n'] + 1\r\n                else:\r\n                        t_balance = traders[t].balance\r\n                        n = 1\r\n                trader_types[ttype] = {'n':n, 'balance_sum':t_balance}\r\n\r\n\r\n        dumpfile.write('%s, %06d, ' % (expid, time))\r\n        printing_column = 0\r\n        for ttype in sorted(list(trader_types.keys())):\r\n                n = trader_types[ttype]['n']\r\n                #to keep the traders in the same columns, make data easier\r\n                if (ttype == 'AA'):\r\n                        s = trader_types[ttype]['balance_sum']\r\n                        dumpfile.write('%s, %d, %d, %f, ' % (ttype, s, n, s / float(n)))\r\n                        printing_column = 1\r\n\r\n                if (ttype == 'ASAD'):\r\n                        if (printing_column == 0):\r\n                                dumpfile.write('%s, %s, %s, %s, ' % ('', '', '', ''))\r\n                        s = trader_types[ttype]['balance_sum']\r\n                        dumpfile.write('%s, %d, %d, %f, ' % (ttype, s, n, s / float(n)))\r\n                        printing_column = 2\r\n\r\n                if (ttype == 'GDX'):\r\n                        for i in range(2 - printing_column):\r\n                                dumpfile.write('%s, %s, %s, %s, ' % ('', '', '', ''))\r\n                        s = trader_types[ttype]['balance_sum']\r\n                        dumpfile.write('%s, %d, %d, %f, ' % (ttype, s, n, s / float(n)))\r\n                        printing_column = 3\r\n\r\n                if (ttype == 'ZIP'):\r\n                        for i in range(3 - printing_column):\r\n                                dumpfile.write('%s, %s, %s, %s, ' % ('', '', '', ''))\r\n                        s = trader_types[ttype]['balance_sum']\r\n                        dumpfile.write('%s, %d, %d, %f, ' % (ttype, s, n, s / float(n)))\r\n                        printing_column = 4\r\n        while printing_column < 4:\r\n                dumpfile.write('%s, %s, %s, %s, ' % ('', '', '', ''))\r\n                printing_column += 1\r\n\r\n\r\n        if lob['bids']['best'] != None :\r\n                dumpfile.write('%d, ' % (lob['bids']['best']))\r\n        else:\r\n                dumpfile.write('N, ')\r\n        if lob['asks']['best'] != None :\r\n                dumpfile.write('%d, ' % (lob['asks']['best']))\r\n        else:\r\n                dumpfile.write('N, ')\r\n        dumpfile.write('\\n');\r\n\r\n\r\n\r\n\r\n\r\n# create a bunch of traders from traders_spec\r\n# returns tuple (n_buyers, n_sellers)\r\n# optionally shuffles the pack of buyers and the pack of sellers\r\ndef populate_market(traders_spec, traders, shuffle, verbose):\r\n\r\n        def trader_type(robottype, name):\r\n                if robottype == 'AA':\r\n                        return Trader_AA('AA', name, 0.00, 0)\r\n                elif robottype == 'ZIC':\r\n                        return Trader_ZIC('ZIC', name, 0.00, 0)\r\n                elif robottype == 'GDX':\r\n                        return Trader_GDX('GDX', name, 0.00, 0)\r\n                elif robottype == 'SNPR':\r\n                        return Trader_Sniper('SNPR', name, 0.00, 0)\r\n                elif robottype == 'ZIP':\r\n                        return Trader_ZIP('ZIP', name, 0.00, 0)\r\n                elif robottype == 'ASAD':\r\n                        return Trader_ASAD('ASAD', name, 0.00, 0)\r\n                else:\r\n                        sys.exit('FATAL: don\\'t know robot type %s\\n' % robottype)\r\n\r\n\r\n        def shuffle_traders(ttype_char, n, traders):\r\n                for swap in range(n):\r\n                        t1 = (n - 1) - swap\r\n                        t2 = random.randint(0, t1)\r\n                        t1name = '%c%02d' % (ttype_char, t1)\r\n                        t2name = '%c%02d' % (ttype_char, t2)\r\n                        traders[t1name].tid = t2name\r\n                        traders[t2name].tid = t1name\r\n                        temp = traders[t1name]\r\n                        traders[t1name] = traders[t2name]\r\n                        traders[t2name] = temp\r\n\r\n\r\n        n_buyers = 0\r\n        for bs in traders_spec['buyers']:\r\n                ttype = bs[0]\r\n                for b in range(bs[1]):\r\n                        tname = 'B%02d' % n_buyers  # buyer i.d. string\r\n                        traders[tname] = trader_type(ttype, tname)\r\n                        n_buyers = n_buyers + 1\r\n\r\n        if n_buyers < 1:\r\n                sys.exit('FATAL: no buyers specified\\n')\r\n\r\n        if shuffle: shuffle_traders('B', n_buyers, traders)\r\n\r\n\r\n        n_sellers = 0\r\n        for ss in traders_spec['sellers']:\r\n                ttype = ss[0]\r\n                for s in range(ss[1]):\r\n                        tname = 'S%02d' % n_sellers  # buyer i.d. string\r\n                        traders[tname] = trader_type(ttype, tname)\r\n                        n_sellers = n_sellers + 1\r\n\r\n        if n_sellers < 1:\r\n                sys.exit('FATAL: no sellers specified\\n')\r\n\r\n        if shuffle: shuffle_traders('S', n_sellers, traders)\r\n\r\n        if verbose :\r\n                for t in range(n_buyers):\r\n                        bname = 'B%02d' % t\r\n                        print(traders[bname])\r\n                for t in range(n_sellers):\r\n                        bname = 'S%02d' % t\r\n                        print(traders[bname])\r\n\r\n\r\n        return {'n_buyers':n_buyers, 'n_sellers':n_sellers}\r\n\r\n\r\n\r\n# customer_orders(): allocate orders to traders\r\n# parameter \"os\" is order schedule\r\n# os['timemode'] is either 'periodic', 'drip-fixed', 'drip-jitter', or 'drip-poisson'\r\n# os['interval'] is number of seconds for a full cycle of replenishment\r\n# drip-poisson sequences will be normalised to ensure time of last replenishment <= interval\r\n# parameter \"pending\" is the list of future orders (if this is empty, generates a new one from os)\r\n# revised \"pending\" is the returned value\r\n#\r\n# also returns a list of \"cancellations\": trader-ids for those traders who are now working a new order and hence\r\n# need to kill quotes already on LOB from working previous order\r\n#\r\n#\r\n# if a supply or demand schedule mode is \"random\" and more than one range is supplied in ranges[],\r\n# then each time a price is generated one of the ranges is chosen equiprobably and\r\n# the price is then generated uniform-randomly from that range\r\n#\r\n# if len(range)==2, interpreted as min and max values on the schedule, specifying linear supply/demand curve\r\n# if len(range)==3, first two vals are min & max, third value should be a function that generates a dynamic price offset\r\n#                   -- the offset value applies equally to the min & max, so gradient of linear sup/dem curve doesn't vary\r\n# if len(range)==4, the third value is function that gives dynamic offset for schedule min,\r\n#                   and fourth is a function giving dynamic offset for schedule max, so gradient of sup/dem linear curve can vary\r\n#\r\n# the interface on this is a bit of a mess... could do with refactoring\r\n\r\n\r\ndef customer_orders(time, last_update, traders, trader_stats, os, pending, verbose):\r\n\r\n\r\n        def sysmin_check(price):\r\n                if price < bse_sys_minprice:\r\n                        print('WARNING: price < bse_sys_min -- clipped')\r\n                        price = bse_sys_minprice\r\n                return price\r\n\r\n\r\n        def sysmax_check(price):\r\n                if price > bse_sys_maxprice:\r\n                        print('WARNING: price > bse_sys_max -- clipped')\r\n                        price = bse_sys_maxprice\r\n                return price\r\n\r\n\r\n\r\n        def getorderprice(i, sched, n, mode, issuetime):\r\n                # does the first schedule range include optional dynamic offset function(s)?\r\n                if len(sched[0]) > 2:\r\n                        offsetfn = sched[0][2]\r\n                        if callable(offsetfn):\r\n                                # same offset for min and max\r\n                                offset_min = offsetfn(issuetime)\r\n                                offset_max = offset_min\r\n                        else:\r\n                                sys.exit('FAIL: 3rd argument of sched in getorderprice() not callable')\r\n                        if len(sched[0]) > 3:\r\n                                # if second offset function is specfied, that applies only to the max value\r\n                                offsetfn = sched[0][3]\r\n                                if callable(offsetfn):\r\n                                        # this function applies to max\r\n                                        offset_max = offsetfn(issuetime)\r\n                                else:\r\n                                        sys.exit('FAIL: 4th argument of sched in getorderprice() not callable')\r\n                else:\r\n                        offset_min = 0.0\r\n                        offset_max = 0.0\r\n\r\n                pmin = sysmin_check(offset_min + min(sched[0][0], sched[0][1]))\r\n                pmax = sysmax_check(offset_max + max(sched[0][0], sched[0][1]))\r\n                prange = pmax - pmin\r\n                stepsize = prange / (n - 1)\r\n                halfstep = round(stepsize / 2.0)\r\n\r\n                if mode == 'fixed':\r\n                        orderprice = pmin + int(i * stepsize)\r\n                elif mode == 'jittered':\r\n                        orderprice = pmin + int(i * stepsize) + random.randint(-halfstep, halfstep)\r\n                elif mode == 'random':\r\n                        if len(sched) > 1:\r\n                                # more than one schedule: choose one equiprobably\r\n                                s = random.randint(0, len(sched) - 1)\r\n                                pmin = sysmin_check(min(sched[s][0], sched[s][1]))\r\n                                pmax = sysmax_check(max(sched[s][0], sched[s][1]))\r\n                        orderprice = random.randint(pmin, pmax)\r\n                else:\r\n                        sys.exit('FAIL: Unknown mode in schedule')\r\n                orderprice = sysmin_check(sysmax_check(orderprice))\r\n                return orderprice\r\n\r\n\r\n\r\n        def getissuetimes(n_traders, mode, interval, shuffle, fittointerval):\r\n                interval = float(interval)\r\n                if n_traders < 1:\r\n                        sys.exit('FAIL: n_traders < 1 in getissuetime()')\r\n                elif n_traders == 1:\r\n                        tstep = interval\r\n                else:\r\n                        tstep = interval / (n_traders - 1)\r\n                arrtime = 0\r\n                issuetimes = []\r\n                for t in range(n_traders):\r\n                        if mode == 'periodic':\r\n                                arrtime = interval\r\n                        elif mode == 'drip-fixed':\r\n                                arrtime = t * tstep\r\n                        elif mode == 'drip-jitter':\r\n                                arrtime = t * tstep + tstep * random.random()\r\n                        elif mode == 'drip-poisson':\r\n                                # poisson requires a bit of extra work\r\n                                interarrivaltime = random.expovariate(n_traders / interval)\r\n                                arrtime += interarrivaltime\r\n                        else:\r\n                                sys.exit('FAIL: unknown time-mode in getissuetimes()')\r\n                        issuetimes.append(arrtime)\r\n\r\n                # at this point, arrtime is the last arrival time\r\n                if fittointerval and ((arrtime > interval) or (arrtime < interval)):\r\n                        # generated sum of interarrival times longer than the interval\r\n                        # squish them back so that last arrival falls at t=interval\r\n                        for t in range(n_traders):\r\n                                issuetimes[t] = interval * (issuetimes[t] / arrtime)\r\n                # optionally randomly shuffle the times\r\n                if shuffle:\r\n                        for t in range(n_traders):\r\n                                i = (n_traders - 1) - t\r\n                                j = random.randint(0, i)\r\n                                tmp = issuetimes[i]\r\n                                issuetimes[i] = issuetimes[j]\r\n                                issuetimes[j] = tmp\r\n                return issuetimes\r\n\r\n\r\n        def getschedmode(time, os):\r\n                got_one = False\r\n                for sched in os:\r\n                        if (sched['from'] <= time) and (time < sched['to']) :\r\n                                # within the timezone for this schedule\r\n                                schedrange = sched['ranges']\r\n                                mode = sched['stepmode']\r\n                                got_one = True\r\n                                exit  # jump out the loop -- so the first matching timezone has priority over any others\r\n                if not got_one:\r\n                        sys.exit('Fail: time=%5.2f not within any timezone in os=%s' % (time, os))\r\n                return (schedrange, mode)\r\n\r\n\r\n        n_buyers = trader_stats['n_buyers']\r\n        n_sellers = trader_stats['n_sellers']\r\n\r\n        shuffle_times = False\r\n\r\n        cancellations = []\r\n\r\n        if len(pending) < 1:\r\n                # list of pending (to-be-issued) customer orders is empty, so generate a new one\r\n                new_pending = []\r\n\r\n                # demand side (buyers)\r\n                issuetimes = getissuetimes(n_buyers, os['timemode'], os['interval'], shuffle_times, True)\r\n\r\n                ordertype = 'Bid'\r\n                (sched, mode) = getschedmode(time, os['dem'])\r\n                for t in range(n_buyers):\r\n                        issuetime = time + issuetimes[t]\r\n                        tname = 'B%02d' % t\r\n                        orderprice = getorderprice(t, sched, n_buyers, mode, issuetime)\r\n                        order = Order(tname, ordertype, orderprice, 1, issuetime, -3.14)\r\n                        new_pending.append(order)\r\n\r\n                # supply side (sellers)\r\n                issuetimes = getissuetimes(n_sellers, os['timemode'], os['interval'], shuffle_times, True)\r\n                ordertype = 'Ask'\r\n                (sched, mode) = getschedmode(time, os['sup'])\r\n                for t in range(n_sellers):\r\n                        issuetime = time + issuetimes[t]\r\n                        tname = 'S%02d' % t\r\n                        orderprice = getorderprice(t, sched, n_sellers, mode, issuetime)\r\n                        order = Order(tname, ordertype, orderprice, 1, issuetime, -3.14)\r\n                        new_pending.append(order)\r\n        else:\r\n                # there are pending future orders: issue any whose timestamp is in the past\r\n                new_pending = []\r\n                for order in pending:\r\n                        if order.time < time:\r\n                                # this order should have been issued by now\r\n                                # issue it to the trader\r\n                                tname = order.tid\r\n                                response = traders[tname].add_order(order, verbose)\r\n                                if verbose: print('Customer order: %s %s' % (response, order) )\r\n                                if response == 'LOB_Cancel' :\r\n                                    cancellations.append(tname)\r\n                                    if verbose: print('Cancellations: %s' % (cancellations))\r\n                                # and then don't add it to new_pending (i.e., delete it)\r\n                        else:\r\n                                # this order stays on the pending list\r\n                                new_pending.append(order)\r\n        return [new_pending, cancellations]\r\n\r\n\r\n\r\n# one session in the market\r\ndef market_session(sess_id, starttime, endtime, trader_spec, order_schedule, dumpfile, dump_each_trade, verbose):\r\n\r\n\r\n        # initialise the exchange\r\n        exchange = Exchange()\r\n\r\n\r\n        # create a bunch of traders\r\n        traders = {}\r\n        trader_stats = populate_market(trader_spec, traders, True, verbose)\r\n\r\n\r\n        # timestep set so that can process all traders in one second\r\n        # NB minimum interarrival time of customer orders may be much less than this!!\r\n        timestep = 1.0 / float(trader_stats['n_buyers'] + trader_stats['n_sellers'])\r\n\r\n        duration = float(endtime - starttime)\r\n\r\n        last_update = -1.0\r\n\r\n        time = starttime\r\n\r\n        orders_verbose = False\r\n        lob_verbose = False\r\n        process_verbose = False\r\n        respond_verbose = False\r\n        bookkeep_verbose = False\r\n\r\n        pending_cust_orders = []\r\n\r\n        if verbose: print('\\n%s;  ' % (sess_id))\r\n\r\n\r\n        while time < endtime:\r\n\r\n\r\n\r\n                # how much time left, as a percentage?\r\n                time_left = (endtime - time) / duration\r\n\r\n                # if verbose: print('\\n\\n%s; t=%08.2f (%4.1f/100) ' % (sess_id, time, time_left*100))\r\n\r\n                trade = None\r\n\r\n                [pending_cust_orders, kills] = customer_orders(time, last_update, traders, trader_stats,\r\n                                                 order_schedule, pending_cust_orders, orders_verbose)\r\n\r\n                # if any newly-issued customer orders mean quotes on the LOB need to be cancelled, kill them\r\n                if len(kills) > 0 :\r\n                        # if verbose : print('Kills: %s' % (kills))\r\n                        for kill in kills :\r\n                                # if verbose : print('lastquote=%s' % traders[kill].lastquote)\r\n                                if traders[kill].lastquote != None :\r\n                                        # if verbose : print('Killing order %s' % (str(traders[kill].lastquote)))\r\n                                        exchange.del_order(time, traders[kill].lastquote, verbose)\r\n\r\n\r\n                # get a limit-order quote (or None) from a randomly chosen trader\r\n                tid = list(traders.keys())[random.randint(0, len(traders) - 1)]\r\n                order = traders[tid].getorder(time, time_left, exchange.publish_lob(time, lob_verbose))\r\n\r\n                # if verbose: print('Trader Quote: %s' % (order))\r\n\r\n                if order != None:\r\n                        if order.otype == 'Ask' and order.price < traders[tid].orders[0].price: sys.exit('Bad ask')\r\n                        if order.otype == 'Bid' and order.price > traders[tid].orders[0].price: sys.exit('Bad bid')\r\n                        # send order to exchange\r\n                        traders[tid].n_quotes = 1\r\n                        trade = exchange.process_order2(time, order, process_verbose)\r\n                        if trade != None:\r\n                                # trade occurred,\r\n                                # so the counterparties update order lists and blotters\r\n                                traders[trade['party1']].bookkeep(trade, order, bookkeep_verbose, time)\r\n                                traders[trade['party2']].bookkeep(trade, order, bookkeep_verbose, time)\r\n                                if dump_each_trade: trade_stats(sess_id, traders, tdump, time, exchange.publish_lob(time, lob_verbose))\r\n\r\n                        # traders respond to whatever happened\r\n                        lob = exchange.publish_lob(time, lob_verbose)\r\n                        for t in traders:\r\n                                # NB respond just updates trader's internal variables\r\n                                # doesn't alter the LOB, so processing each trader in\r\n                                # sequence (rather than random/shuffle) isn't a problem\r\n                                traders[t].respond(time, lob, trade, respond_verbose)\r\n\r\n                time = time + timestep\r\n\r\n\r\n        # end of an experiment -- dump the tape\r\n        exchange.tape_dump('transactions.csv', 'w', 'keep')\r\n\r\n\r\n        # write trade_stats for this experiment NB end-of-session summary only\r\n        trade_stats(sess_id, traders, tdump, time, exchange.publish_lob(time, lob_verbose))\r\n\r\n\r\n\r\n#############################\r\n\r\n# # Below here is where we set up and run a series of experiments\r\n\r\n\r\nif __name__ == \"__main__\":\r\n\r\n        # set up parameters for the session\r\n\r\n        start_time = 0.0\r\n        end_time = 330.0\r\n        duration = end_time - start_time\r\n\r\n\r\n        # schedule_offsetfn returns time-dependent offset on schedule prices\r\n        #def schedule_offsetfn(t):\r\n        #        pi2 = math.pi * 2\r\n        #        c = math.pi * 3000\r\n        #        wavelength = t / c\r\n        #        gradient = 100 * t / (c / pi2)\r\n        #        amplitude = 100 * t / (c / pi2)\r\n        #        offset = gradient + amplitude * math.sin(wavelength * t)\r\n        #        print int(round(offset, 0))\r\n        #    \treturn int(round(offset, 0))\r\n\r\n        def schedule_offsetfn(t):\r\n                return int((t % 75)/2)\r\n\r\n        # def schedule_offsetfn(t):\r\n        #         return int(math.sin(t/30))\r\n        #\r\n        # def schedule_offsetfn(t):\r\n        #         if (t % 100 < 50):\r\n        #                 return 5\r\n        #         else:\r\n        #                 return -5\r\n\r\n\r\n# #        range1 = (10, 190, schedule_offsetfn)\r\n# #        range2 = (200,300, schedule_offsetfn)\r\n\r\n# #        supply_schedule = [ {'from':start_time, 'to':duration/3, 'ranges':[range1], 'stepmode':'fixed'},\r\n# #                            {'from':duration/3, 'to':2*duration/3, 'ranges':[range2], 'stepmode':'fixed'},\r\n# #                            {'from':2*duration/3, 'to':end_time, 'ranges':[range1], 'stepmode':'fixed'}\r\n# #                          ]\r\n\r\n\r\n\r\n        range_supply1 = (10,50)\r\n        range_supply2 = (25,35)\r\n        range_supply3 = (10,50)\r\n        range_supply4 = (20,60)\r\n        supply_schedule = [ {'from':start_time, 'to':end_time, 'ranges':[range_supply1], 'stepmode':'fixed'},\r\n                            #{'from':180, 'to':330, 'ranges':[range_supply2], 'stepmode':'fixed'},\r\n                            #{'from':330, 'to':480, 'ranges':[range_supply3], 'stepmode':'fixed'},\r\n                            #{'from':330, 'to':end_time, 'ranges':[range_supply3], 'stepmode':'fixed'},\r\n                          ]\r\n\r\n        range_demand1 = (10,50)\r\n        range_demand2 = (10,50)\r\n        range_demand3 = (25,35)\r\n        range_demand4 = (20,60)\r\n        demand_schedule = [ {'from':start_time, 'to':end_time, 'ranges':[range_demand1], 'stepmode':'fixed'},\r\n                            #{'from':180, 'to':330, 'ranges':[range_demand2], 'stepmode':'fixed'},\r\n                            #{'from':330, 'to':480, 'ranges':[range_demand3], 'stepmode':'fixed'},\r\n                            #{'from':330, 'to':end_time, 'ranges':[range_demand3], 'stepmode':'fixed'},\r\n                          ]\r\n\r\n        order_sched = {'sup':supply_schedule, 'dem':demand_schedule,\r\n                       'interval':30, 'timemode':'periodic'}\r\n\r\n        # buyers_spec = [('AA',2),('SHVR',10),('ZIC',10),('ZIP',10)]\r\n        # sellers_spec = buyers_spec\r\n        # traders_spec = {'sellers':sellers_spec, 'buyers':buyers_spec}\r\n        #\r\n        # # run a sequence of trials, one session per trial\r\n        #\r\n        # n_trials = 10\r\n        # tdump=open('avg_balance.csv','w')\r\n        # trial = 1\r\n        # if n_trials > 1:\r\n        #         dump_all = False\r\n        # else:\r\n        #         dump_all = True\r\n        #\r\n        # while (trial<(n_trials+1)):\r\n        #         trial_id = 'trial%04d' % trial\r\n        #         market_session(trial_id, start_time, end_time, traders_spec, order_sched, tdump, False, True)\r\n        #         tdump.flush()\r\n        #         trial = trial + 1\r\n        # tdump.close()\r\n        #\r\n        # sys.exit('Done Now')\r\n\r\n\r\n\r\n\r\n        # run a sequence of trials that exhaustively varies the ratio of four trader types\r\n        # NB this has weakness of symmetric proportions on buyers/sellers -- combinatorics of varying that are quite nasty\r\n\r\n\r\n        n_trader_types = 4\r\n        equal_ratio_n = 4\r\n        n_trials_per_ratio = 15\r\n\r\n        n_traders = n_trader_types * equal_ratio_n\r\n\r\n        fname = '15_balances_withZIP_M1_periodic.csv'\r\n\r\n        tdump = open(fname, 'w')\r\n\r\n        min_n = 0\r\n\r\n        trialnumber = 1\r\n\r\n        tdump.write('%s, %s, ' % ('expid', 'time'))\r\n        for f in range(4):\r\n                tdump.write('%s, %s, %s, %s, ' % ('type', 'balance', 'number of traders', 'profit per trader'))\r\n        tdump.write('\\n');\r\n\r\n        # buyers_spec = [('GDX', 11), ('ZIP', 11)]\r\n        # sellers_spec = buyers_spec\r\n        # traders_spec = {'sellers':sellers_spec, 'buyers':buyers_spec}\r\n        # print buyers_spec\r\n        # trial = 1\r\n        # while trial <= n_trials_per_ratio:\r\n        #        trial_id = 'trial%07d' % trialnumber\r\n        #        market_session(trial_id, start_time, end_time, traders_spec,\r\n        #                       order_sched, tdump, False, True)\r\n        #        tdump.flush()\r\n        #        trial = trial + 1\r\n        #        trialnumber = trialnumber + 1\r\n\r\n        trdr_1_n = min_n\r\n        while trdr_1_n <= n_traders:\r\n               trdr_2_n = min_n\r\n               while trdr_2_n <= n_traders - trdr_1_n:\r\n                       trdr_3_n = min_n\r\n                       while trdr_3_n <= n_traders - (trdr_1_n + trdr_2_n):\r\n                               trdr_4_n = n_traders - (trdr_1_n + trdr_2_n + trdr_3_n)\r\n                               if trdr_4_n >= min_n:\r\n                                       buyers_spec = [('AA', trdr_1_n), ('GDX', trdr_2_n),\r\n                                                      ('ASAD', trdr_3_n), ('ZIP', trdr_4_n)]\r\n                                       sellers_spec = buyers_spec\r\n                                       traders_spec = {'sellers':sellers_spec, 'buyers':buyers_spec}\r\n                                       # print buyers_spec\r\n                                       trial = 1\r\n                                       while trial <= n_trials_per_ratio:\r\n                                               trial_id = 'trial%07d' % trialnumber\r\n                                               market_session(trial_id, start_time, end_time, traders_spec,\r\n                                                              order_sched, tdump, False, True)\r\n                                               tdump.flush()\r\n                                               trial = trial + 1\r\n                                               trialnumber = trialnumber + 1\r\n                               trdr_3_n += 1\r\n                       trdr_2_n += 1\r\n               trdr_1_n += 1\r\n        tdump.close()\r\n\r\n        print trialnumber\r\n"
  }
]