Tour de Finance (TDF)
The Tour de Finance (TDF) is an open-source paper-trading system designed to facilitate the research of and education in the application of controls in finance. Using TDF, several users can join competitions in which they write autonomous scripts which retrieve historical stock prices on the S&P 500 and then make intelligent trades based on that information.
Table of Contents
- Admins
- Installing and Running a VirtualBox Image of TDF
- Getting Started: Creating an Admin Account
- Creating a League
- Users
Admins
Installing from Source
If you wish to install TDF from source (recommended for large-scale deploys and contributors), you can pull the code from github.com/idealabs/tdf.
The README in the root of this repo will give more detailed instructions on how to install the dependencies and run the TDF server.
Installing and Running a VirtualBox Image of TDF
A recent build of TDF can be downloaded, imported into, and run from Oracle VM VirtualBox without requiring the installation of the TDF source or its dependencies. To do this:
- Download and Install VirtualBox from virtualbox.org/wiki/Downloads. This site will have installation instructions particular to your host operating system's needs.
- Download the TDF Virtual Appliance by clicking the link idealabs.byu.edu/vms/tour-de-finance.ova. The application will automatically download into your browser's default download directory.
-
Start the VirtualBox application. You should get a dashboard similar to that shown below.
-
From the toolbar, navigate to and click on
File > Import Appliance...
(see figure below). This will open a dialogue box titledImport Virtual Appliance
. -
Within the
Import Virtual Appliance
dialogue box (see figure below), click on the buttonOpen appliance...
This will open your operating system's file browser. -
Within the file browser opened in the previous step, navigate to the location where you downloaded the
TDF Virtual Appliance in Step 2. Double click on the file
tour-de-finance.ova
or select it and clickOpen
. You will return to theImport Virtual Appliance
dialogue box. -
Within the
Import Virtual Appliance
dialogue box, verify that the path to thetour-de-finance.ova
, shown to the right of theOpen appliance...
button (see figure below), is correct. If so, click on theNext
button at the bottom of the dialogue box. -
The
Import Virtual Appliance
dialogue box now contains a series of options defining the import (see figure below). Leave these options at their defaults and click theImport
button at the bottom of the dialogue box. A progress bar (see figure below) will appear showing the progress of the import. -
Once the import is completed, you will return to the VirtualBox dashboard. As shown in the figure below,
you should now see a new entry in the left column titled
deploy_...
(this name may change in future releases). Highlight this entry and click on the greenStart
button near the top of the dashboard. The TDF instance will begin powering up. -
While the TDF instance is powering up, a series of dialogue boxes may appear giving information about and instructions
on the instance (such as those shown in the figures below). Click on the
Next
button or theOk
button on any of these dialogue boxes that appear. -
Your machine will boot up, showing details in the console such as those shown in the figure below.
-
Eventually, your machine will be booted and the console will display a prompt to login as shown in the figure below.
TDF is running in the background of this machine, so you can now minimize the virtual machine since you do not need to
login or perform any additional action here.
-
Now you can access TDF Web Application (see the figure below) on the machine running the virtual machine through the
url http://localhost:3000. If you want to access TDF from a remote machine, you will
need to forward port 3000 of this machine to a public location.
-
If you ever need to close the virtual machine, just try to close it like any other program. (Red box in upper right
hand corner). Then select
Power off the Machine
when the subsequent dialogue box (see the figure below) opens. TDF will then be exited safely.
Getting Started: Creating an Admin Account
As an admin, the first thing you will need to do is to create an admin account. To do this, use a browser to navigate to the TDF
Webapp home page at localhost:3000. On this page, you should see a section titled
New to Tour de Finance? Create an Account
. An admin account is a regular account with the username
admin
; therefore, to create an admin account, fill out all the fields in this section and choose the username
to be admin (see figure below).

After you have created an admin account, you will be automatically logged in as the admin and then redirected to the
Existing Leagues
page, as shown below (note that any time you try to access the home page after logging
in with any account, you will be redirected to this page).

Creating a League
A league is a container that holds a set of players which trade and compete on a set of rules. Players will not be able to compete unless they join a league.
To create a new league, log in to the admin account (if you have not done so already) and navigate to the
Existing Leagues
page by either navigating to the TDF home or by clicking on the
Leagues
link on the top navigation bar (see figure at the end of the previous section).
This page shows a list of all the leagues created within TDF. Since this is a new TDF instance, this list will be empy. Click
on the Add a New League
button to begin the process of creating a new league.
You will now navigate to a page allowing you to set the various rules under which agents in the league will compete (see figures below). In summary, the rules are as follows:
- General Settings
- League Name: The name of the league
- Competition Phases
- Trial Period Start: The trial period is the period in which users can create new agents, test their algorithms, and reset as many times as they want. In essence, it is a competition with more lax rules and no winner is chosen at the end
- Competition Period Start: The competition period locks the league so that no agents can be created or reset. Agents are reset immediately when the competition begins.
- Competition Period End: At the end of the competition, agents are no longer able to trade and a winner is chosen (currently based only on who has the most money, but more metrics will be implemented in future releases).
- Trade Settings
- Starting Cash: The amount of cash in each agent's account upon creation and immediately following each reset.
- Leverage Multiple: Defines how much each agent is able to leverage and short sell.
If leverage and short selling is to be disallowed, set the leverage multiple to 0.
Otherwise, let the leverage multiple bem
, the total portfolio value after a proposed trade bev
and the sum of the negative value of the portfolio (i.e. the sum of the cash, if cash is less than zero, with the value of each security owed due to short-selling) ben
. Then a trade will be disallowed ifv < m * n
. Further, if this condition fails for any given agent when stock prices update, then random securities in the agent's portfolio will be sold until the condition passes. - Redistribution Dynamics: If enabled, agents' cash will be redistributed between portfolios depending on performance simulating investors in funds leaving poor-performing funds and joining higher-performing funds. This leads to a more fair competition incentivizing intelligent trading over lucky trading (see the paper Competion Dynamics in a Virtual Fund Management System: Tour de Finance for more details).


Once you have set your rules to your satisfaction, click on the Save
button at the bottom of the page.
You will now return to the Existing Leagues
where you should see a new entry for your new league (see
figure below).

Users
Registering
To create a new user with TDF, visit the TDF home page. Fill out the information requested in the New to Tour de
Finance? Create an Account
and click the Sign Up
button (see figure below).

If registration is successful, you will automatically be logged in and redirected to the Existing Leagues
page (see figure below).

Creating an Agent
To create an agent, you need to choose the league in which it will compete. On the Existing Leagues
page,
click the View League
button next to the league in which you wish to compete. You will be taken to
the League Standings
page for this league (see the figure below).

The first section on this page, titled Current Standings
will show a graph of the portfolio values of the
agents over time during the trial and competition periods of the league. Since there are no agents in the league shown
above, this graph is empty.
The second section on this page, titled Agents in League "<League Name>"
, lists all agents registered
for this league as well as a brief summary of the agent's standing in the league. Since there are no agents registered for
the league shown in the image above, this list is empty. To create a new agent, click on the
Create an Agent
button to the right of the section header. You will be taken to a page allowing you to
enter the details about your new agent (see image below).

Give your new agent a name, and if you want, give a brief description. When finished, click on the Submit
button. You will then be redirected to the Agent View
page for the agent (see figure below).

On this page, note the agent's Public ID and API Key. These values are necessary to connect a back-end script to trade on this agent.
Making a Trade through the Webapp
TDF allows you to make manual trades on an agent through the webapp. On the Agent View
page, click
on the Trade
button near the top of the page (you can also access this button next to the agent's entry
on the League View
page). This will navigate you to the page shown below.

Within the Trade
section of this page, input any of the ticker symbols for a security in the S&500,
and choose the quantity of that security to buy (positive quantity) or sell (negative quantity). If you want to trade on more
than one security, click on the Add a Security
button and a new line will appear allowing you to make
another trade.
For example, in the image above, a trade has been set up to buy 20 shares of Google and sell 15 shares of Apple.
Once you have set up your trade, click on the Execute Trade
button. TDF will then adjust your cash
and security accounts according to the current value of each of the securities chosen.
If the league is currently in its trial period, you can also click on the Reset Trades
button to revert your
portfolio to owning no securities and to having the default amount of cash in your account.
Connecting a Script to TDF
You can also make trades using any script running off a computer that has access to the TDF server (if the TDF server is running on a public url, then any script with access to the internet can access it).
Let http://<host>/
be the URL to access the TDF home page. Further, let
<agent-id>
and <api-key>
be the Public ID and API Key
respectively found on the Agent View
page. Finally, let the n
securities which you wish
to trade have ticker symbols <symbol-1>, <symbol-2>, ..., <symbol-n>
, and the quantities
of each to buy/sell be <quantity-1>, <quantity-2>, ..., <quantity-n>
where
<quantity-i>
is positive if you wish to buy <security-i>
and negative if you wish
to sell <security-i>
.
Then, any script can make a trade by opening the url
http://<host>/agents/trade/<agent-id>?apikey=<api-key>&<security-1>=<quantity-1>&<security-2>=<quantity-2>&<...>&<security-n>=<quantity-n>
For example, the following MATLAB script buys 20 shares of Google and sell 15 shares of Apple:
SITE = 'http://localhost:3000/agents/trade/; % The agent's public id and private api key can both % be found on the agent's view on the TDF site AGENT_ID = '52a5ddc7bcdd762351000fad'; API_KEY = 'uyftqmgojiiygcljlqqmvbfrgqmqdhyr'; URL = strcat(SITE, AGENT_ID, '?apikey=', API_KEY); buy = strcat(URL, '&GOOG=20', '&AAPL=-15'); urlread(buy);
Using the TDF Queries
Again, let http://<host>/
be the URL to access the TDF home page.
The following queries may be helpful for scripts to gain the information they need to make intelligent trades:
List of Tradable Ticker Symbols
You can see all of the ticker symbols tracked by TDF through http://<host>/history/
.
The result will be a JSON array in the following format:
[ "<security-1>", "<security-2>", ... ]
You can also access this information on the front-end web app by accessing http:/<host>/#!/histories/
.
Status and History of a Security
You can see the details, including current and historical prices, of a particular security represented by ticker symbol
<symbol>
through
http://<host>/history/<symbol>
.
The result will be a JSON object in the format
{ "current": { "ask": <real-time ask price>, "bid": <real-time bid price>, "last": <real-time last price> }, "ask": { <JavaScript date of most recently scraped data>: <ask at date>, ... <JavaScript date of first scraped data>: <ask at date> }, "bid": { <JavaScript date of most recently scraped data>: <bid at date>, ... <JavaScript date of first scraped data>: <bid at date> }, "last": { <JavaScript date of most recently scraped data>: <last at date>, ... <JavaScript date of first scraped data>: <last at date> } }
You can also et an overview and a graph of this information from the front-end web app through
http:/<host>/#!/histories/<symbol>
.
Current Status of All Securities
You can use the following query to return the current status (ask, bid, and/or last prices) of all securities in the S&P 500:
[host]/currentstatus?select=[select]
Select can be one of "all", "ask", "bid", and "last" (without the quotes). If no select parameter is passed, or if it is not one of these options, the query will default to "all."
If [select] is "all", the result will be a JSON object in the following format:
{ "[symbol]": { ask: [current ask price of [symbol]], bid: [current bid price of [symbol]], last: [current last price of [symbol]] }, ... }
If [select] is "ask," then the result will be a JSON object in the following format:
{ "[symbol]": [current ask price of [symbol]], ... }(and similarly for "bid" and "last").
History of All Securities
You can use the following query to return the historical prices of all securities:
[host]/allhistories?select=[select]&n=[N]
Select can be one of "all", "ask", "bid", and "last" (without the quotes). If no select parameter is passed, or if it is not one of these options, the query will default to "all."
n can be any positive integer. If no n query parameter is passed, the query will default to n=12. This defines the number of times which the server has recorded that the query will return (e.g. if the server fetches data every hour, n=12 returns the last 12 hours of data).
If select is "all", then the result will be a JSON object in the following format:
{ [JavaScript date of first most recently scraped data]: { "[symbol]": { ask: [ask price of [symbol]], bid: [bid price of [symbol]], last: [last price of [symbol]] }, ... }, ..., [JavaScript date of nth most recently scraped data]: { ... } }
If select is "ask", then the result will be a JSON object in the following format:
{ [JavaScript date of the first most recently scraped data]: { "[symbol]": [ask price of [symbol]] }, ..., [JavaScript date of the nth most recently scraped data]: { ... } }(and similarly for "bid" and "last").
Status of an Owned Agent
Using the same information used to make a back-end trade, you can see an agent's current portfolio composition and value
through
http://<host>/agents/<agent-id>/composition?apikey=<api-key>
.
The result will be a JSON object in the format
{ "uninvested_cash": <Total Uninvested Cash>, "<Symbol 1>": { "quantity": <Number of shares invested in <Symbol 1>>, "price": <Price of one share of <Symbol 1>>, "value": <Value of investment in <Symbol 1>, quantity * price> }, ... "<Symbol n>": { "quantity": <Number of shares invested in <Symbol n>>, "price": <Price of one share of <Symbol n>>, "value": <Value of investment in <Symbol n>, quantity * price> }, "total_value": <Total value of portfolio = uninvested_cash + sum_{i = 1 to n} value(<symbol i>)> }