These applications provide a widely adaptable Continuous Double Auction (CDA) in oTree v6 via a complete implementation of an experimental asset market with multiple continuously operating traders and multiple assets. Permission to use this software is granted for educational and academic purpose with the requirement of citation.
- Overview
- JavaScript
- Installation
- Sequence
- Data download
- Settings and parametrisation
- Disclaimer
- References
Continuous double auctions are provided in four apps.
The applications singleAsset
and singleAssetInfo
cover markets with a single asset while nAssets
and nAssetsInfo
cover market environments with multiple (n) assets.
Meanwhile, singleAsset
and nAssets
provide baseline applications with all market functionalities that target users who require intensive modifications.
singleAssetInfo
and nAssetsInfo
provide versions, in which participants are acquainted with private information about the buyback value(s).
The latter applications mimic the experiment in Palan et al. (2020), in which the buyback value is defined by coins in a jar and private information consists of accurate information about a partition of coins.
To implement an application without major modifications of the code for classroom experiments, you may have a look at the step-by-step description.
There are existing, well-developed packages for CDA markets, notable examples are otree_markets which uses LEEPS lab's redwood framework, high frequency trading, otree-double-auction, and otree etf cda. However, to the best of my knowledge, there is no software which is supported by the new oTree version 6 and thus not supported by newer python version without a virtual environment. This is why, I started to create this app primarily for classroom games.
This application adds some more useful tools; for example, participants are now able to specify any volume they want to transact.
Given the simultaneous placement of limit orders and acceptance via market orders, these applications use live pages extensively.
As a consequence, I do also use JavaScript and call the functions liveSend() and liveRecv().
The corresponding files are placed in the _static
folder, which must be loaded at the beginning of a html in the global_scripts block.
As another consequence, an error window pops up on clients screen via <noscript>, when JavaScripts are blocked.
The purposes of individual JavaScript files are depicted in README_JavaScript.md.
These applications are developed with oTree 6.0.0 using python 3.11.5. Running an online or classroom session, you may follow the instructions in ExpEcoWorkflow_course_repository. To make adaptions to these applications, you may need to download both python, which is available free of charge at python.org/downloads/, and oTree via the terminal as described by oTree Setup with:
pip3 install -U otree
Note that developers of oTree do not recommended the use of text editors to most users and provide oTree Studio instead. However, to the best of my knowledge there is no easy workaround such that the order book is continuously updated and such that orders can be transmitted continuously without using the text editor. Since my background is not quite computer science, I guess that most code is straightforward to understand. This said, I am humble enough to add that I benefited sharing the name with a very talented, sophisticated, and patient brother who explained this new world to me. Finally, the otree team implemented a very powerful and easily applicable tool for continuous communication between client and server via the live_method().
To run CDA online, you need an online deployment via some server setup. The oTree team recommends the use of the heroku server, which now charges a little fee. The current free way to go is via a github account and the cloud service render.com. For more detailed instructions you are invited to visit oTree: Online Deployment. The latter free instances should be fine for little classroom demonstrations, however risky for experimental sessions.
Instructions are inspired by Palan et al. (2020) and Merl et al. (2023).
The corresponding files that are loaded in Instructions.html
and include most of the text is placed at _templates/instructions*.html
.
In the instructions, I focus on markets with a single asset and private information provision such that information consists of accurate information about the amount of coins of specific coin values in a jar.
One information is gathered at the end of the instruction page, which is the number of actual participants. By clicking the 'I read and understand the instructions' button, participants are sent to the waiting page but they are also set to be actively participating. This allows classroom instructors to start a session with a much higher number of participant links in otree, although just a fraction is actually participating. Given that some student come late to classes, this can be an advantage.
As all participants arrive in the waiting page, i.e., when the experimenter 'advances' non-participating users to the waiting page, some substantial variables are initialised. First, I retrieve from the config variables, which are specified when a nes session is created, whether participants roles are fixed or can change in each round. All participates can either be inactive observers or traders with distinguishable private information. There are multiple further substantial variables defined in the wait-to-start page:
Within the function initiate_group(), participants are counted (count_participants()) and the asset value is defined (define_asset_value()). Within apps with private information, the role structure (define_role_structure()) and role information (define_role_information_structure()) is defined. Participants' roles are also assigned (assign_types()) in round 1 or when roles are randomly assigned each round. Changes of the role or information structure, i.e. number of participants of a particular role, the information content, overlaps, etc. are set in these functions.
Within the function set_player_info(), I distribute information according to the information structure in function assign_role_attr() and distribute participant characteristics. Respectively in apps without information distribution, the function set_player() distributes participant characteristics only, i.e., whether they are active traders or inactive observers. Within the function initiate_player(), I distribute initial endowments.
Just at the very beginning of the first payoff-relevant period, a short reminder is shown that asks for any further open question.
Before the market starts, participants receive information about their future role, their endowment, and private information in tabular form. It may be advisable to set a timeout for this page.
This page makes sure that all participants start simultaneously, saves the market start time, and sets the market end time.
In the market page the information of the pre-market page is shown again. In addition, the entire marketplace is displayed, i.e., where participants can place a limit order, the order book that allows to accept market orders, and a graphic time series of the market transaction prices. There is also a box with information about the last own transactions and messages about order rejections.
In the waiting page before results, the period income and final payout is calculated. It is important to run these calculations before the actual result page as random number generators would be re-run with each reload of the page and change the result.
After the market timeout, participants see the result page, which provides information about the actual buyback value of the asset and the period income. I specify the profit function in the function calc_period_profits() which reads:
In the end of the very last round, participants see a summary of their payoff and a table including each period income. The final payoff is a random draw of the previous period payoffs defined in the function calc_final_profit().
I implemented a customised admin report that includes participants' period profits and a graphic.
The graphic visualises time series of trading activity in means of best bid, best ask, and transaction prices.
The entries are defined in the function vars_for_admin_report() in __init__.py
and the report's layout is defined in _templates/admin_report.html
.
I implemented special data tables for limit orders, transactions, and all kind of orders, as I implemented the tables for recordings of the bid-ask spread and a protocol of automatic messages.
For these tables, I define customised data download in the respective __init__.py
files.
Thus, changes in the customised data structure of orders require adjustments of the download process too.
Especially for the applications with multiple assets, I register entries as stings in JSON format, for example {assetID: entry}. These variables may need some attention to decode. Currently, I use the package jsonlite in R.
There are five market settings that are set when a new session is created. As usual in oTree, you are asked to choose the application and set the number of participants. When clicking on configurate session you can set 4 more parameters, which are the market time in seconds, whether roles are randomised between rounds, whether short selling and buying on margin is allowed.
Other settings and parameters are either set in the respective __init__.py
file or transmitted via in comma separated format.
For example, the number of (trial) rounds, the endowment and payment parameters are set in the constants (C) table.
Furthermore, with n assets you can specify in the __init__.py
file the names of the assets via the list ASSET_NAMES.
For more substantial changes, e.g. changes of the role, endowment, or profit structures, please adapt the respective functions.
I think I found a quite convenient approach to distribute information.
This approach is based on information partitions and truthful disclosure of partitions.
The partition names are specified in the __init__.py
file via the list PARTITIONS_NAMES and the unit value via the list PARTITIONS_UNIT_VALUES.
The amount of units of each partition is specified in comma separated format in the _parameters/assetPartition.csv
file.
Different information structures can similarly be implemented.
Modifications must consider various processes.
There is the process how information is loaded in the function define_asset_value() and in the AssetsPartitions table, how roles are attributed with information in the function define_role_information_structure(), and how participants are attributed with information in function assign_role_attr().
It is also very important to adjust the way how information is visualised to participants in the respective JavaScript file, which is either _static/sCDAstatic/scriptSAssetInfo.js
or _static/nCDAstatic/scriptnAssetsInfo.js
.
The code is provided for educational and academic purposes and you agree that you use such code entirely at your own risk.
-
Chen, Daniel L., Martin Schonger, Chris Wickens. 2016. oTree—An open-source platform for laboratory, online, and field experiments. Journal of Behavioral and Experimental Finance 9 88-97.
-
Merl, Robert, Stefan Palan, Dominik Schmidt, Thomas Stöckl. 2023. Insider trading legislation and trader migration. Journal of Financial Markets 66.
-
Palan, Stefan, Jürgen Huber, Larissa Senninger. 2020. Aggregation mechanisms for crowd predictions. Experimental Economics 23 (3) 788-814.