Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
An agent is available to send orders to any OrderBook of the market. Agents can have a behavior or not. If not, you will just be able to use them to send orders, if yes, you will be able to leave them living in the Market. In that case, frequently, the market will ask all agents wether if they want to send an order or not.
The previous agent was just there to send orders and to allow the experimenter to track its portfolio. Nevertheless you will probably need to build agents evolving alone in the market. The Market's method {{{runOnce()}}} is a method which question all agents in a random order. Calling this method twice will not deliver the same order, but you can be sure that all the agents will be questioned at least once. This method itself calls {{{decideOne()}}} in each agent. It is this method that describes the agent's behavior. The simplest way to do so, is to build what is usually called a Zero Intelligent Trader : and agent which chooses randomly a price, a quantity and a direction for a given LimitOrder. It never takes care of its cash or amount of assets in portfolio, so it will probably be bankrupt extremely quickly. In the following example, the ZIT will always send an Order, but one could easily design another ZIT who decides to return a "null" action one time out of three for example.
{{{
package test;
import atom.core.*;
public class MyOwnIT extends Agent {
public MyOwnIT(String name, long cash)
{
super(name, cash);
}
protected OrderItf decideOne(String invest, char news)
{
// the aim of the behavior is to decide the value of these 3 variables :
char dir;
int quty;
long price;
// She choose randomly what to do
if (MyRandom.nextDouble() > 0.5)
dir = LimitOrder.BID;
else
dir = LimitOrder.ASK;
quty = 1 + (int) (Math.random() * 100);
price = 1 + (int) (Math.random() * 1000);
return new LimitOrder(dir, quty, price);
}
}
}}}
This agent is already present in the ATOM package. It is called ZIT0 and can directly be used in any of your own simulations. This is relatively straightforward : once registered in the market, you just have to ask several times {{{runOnce}}} to observe how the agents evolve in the market.
<html> <p><img src=atom_img/case3.png style="width: 12cm;" alt="atom artificial trading agents market"/> </html>
{{{
package atom.test;
import atom.core.*;
public class TestZIT {
public static void main(String args[]) {
int nbAgents = 10;
int rounds = 500;
MarketPlace m = new MarketPlace();
OrderBook ob = new OrderBook("lvmh");
m.addNewOrderBook(ob);
for (int i = 1; i <= nbAgents; i++) {
Agent a = new MyOwnIT("agent_" + i, 100000);
a.setInvestment("lvmh", 1000);
m.addNewAgent(a);
}
for (int i = 1; i <= rounds; i++)
m.runOnce();
System.out.println("nb fixed prices : " + ob.getNumberOfPricesFixed());
System.out.println("nb used orders : " + ob.getNumberOfOrdersReceived());
System.out.println("leaving ask size : " + ob.getNumberOfAsk());
System.out.println("leaving bid size : " + ob.getNumberOfBid());
}
}
}}}
![[Exercices B]]
{{{
package v12.test;
import v12.*;
import v12.agents.*;
import java.util.*;
public class WikiUseCase3 {
public static void main(String[] args) {
final String APPLE = "AAPL";
Simulation sim = new MonothreadedSimulation();
// Let's see what is happenning when the simulation is running
sim.setLogger(new Logger(System.out));
// Orderbook creation to represent the Apple asset
sim.addNewOrderBook(APPLE);
// Adding 100 agents to the simulation
for (int i=0; i<50; i++) {
sim.addNewAgent(new ZIT("zit"+i, 1000000));
sim.addNewAgent(new ModerateAgent("mod"+i, 1000000));
}
// Let's launch the simulation
sim.run(Day.createEuroNEXT(10, 100, 10), 1);
}
}
}}}
To analyze results produced by ATOM, you will often need to use other tools. One needs frequently to plot a curve containing the evolution of prices generated by ATOM. In the following, one can find explanations about how to do construct such plots.
In this example we used the {{{Generate}}} command to create 100 ZIT agents with three OrderBook for 8000 round of talks (see [[Agents Behavior]]) to generate {{{ExampleFile.atom}}}:
{{{
java -cp atom.jar v12.Generate 100 3 8000 > ExampleFile.atom
}}}
The {{{~ExampleFile.atom}}} contains all information generated by the simulator (prices, orders, agent update, day notifications ...) for all orderbooks.
If you want to plot prices from one specific orderbook, it's easier to filter the generated prices lines for this orderbook:
{{{
# Filter prices from the orderbook named 'lvmh1'
grep 'Price;LVMH1' ExampleFile.atom > data
}}}
Please notice that some tools will need to have the file with a ''.csv'' suffix before loading it. In this case one will have to modify the name of the file.
!! Using ~OpenOffice
Launch [[OpenOffice|http://www.openoffice.org]] and create a new Spreadsheet
Then Insertion/Sheet from File ... select your file (''ExampleFile.atom'', as computed previously) then semi-column as separator and click ok twice.
You then have all your data in OOCalc and you can analyze, plot, or do what you want with these data
!! Using Gnuplot
Install [[gnuplot|http://www.gnuplot.info/]]
BEWARE: The default separator in gnuplot is a space or tabulation but ATOM uses ';'.
Content of {{{generate.gnuplot}}} file:
{{{
set datafile separator ";"
# Draw all prices graph
plot 'data' using 3 with lines
# Draw prices by selecting one value every one hundred prices
plot 'data' every 100 using 3 with lines
# Same a s above but with smooth lines
plot 'data' every 100 using 3 smooth csplines
# Draw only the first hundred prices
plot 'data' every ::1::100 using 3 smooth csplines
# Saving the graph to a PDF file
set terminal push
set terminal pdf
set output "data.pdf"
replot
set output
set terminal pop
}}}
You can plot your data with this command line: {{{gnuplot generate.gnuplot}}}
If you need to plot several orderbooks, first generate a log file:
{{{
java -cp atom.jar v12.Generate 100 3 50 | grep Tick > data.csv
}}}
Then, within {{{gnuplot}}} you can plot all the series simultaneously by using tick lines:
{{{
plot [][10000:15000] "data.csv" every ::0::100 using 6 with lines title "LVMH1", every ::0::100 using 10 with lines title "LVMH2", every ::0::100 using 14 with lines title "LVMH3",
}}}
Here are some explanations to customize the above plot command:
* {{{[10000:15000]}}} fixes prices range,
* {{{every ::0::100}}} fixes ticks range,
* {{{using 6 with lines}}} defines which columns should be used (here 6 corresponds to the first orderbook price column),
* {{{title "LVMH1"}}} to define the legend for this asset.
If you want to generate nice bollinger bars, like this example:
<html> <p><img src="atom_img/bollinger.png" style="width: 12cm; display: block; margin: 0 auto;" alt="bollinger" /> </html>
You first have to filter the log file to retrieve only day traces: {{{grep Day data.log > data2}}}
Then with {{{gnuplot}}}, you generate the graph by using these commands:
{{{
set datafile separator ";"
plot "data2" using :4:5:6:7 with financebars
}}}
!! Using R
Install the [[R package|http://www.r-project.org/]].
{{{
# To load your price file (named 'data' in this example)
data <- read.csv("data", sep=" " , header=FALSE)
head(data)
# Draw the price graph
plot(data$V3, type="l")
# Same as above with smoothing
plot(spline(data$V3[1:100]),type="l")
# Draw prices by selecting one value every one hundred prices
plot(data$V3[seq(1,dim(data)[1], by=100)],type="l")
# Draw only the first hundred prices
plot(data$V3[1:100], type="l")
# Saving the graph to a PDF file
pdf(file="data.pdf")
plot(data$V3, type="l")
dev.off()
}}}
ATOM is able to use several OrderBooks simultaneously. You can then develope agents able to behave as arbitragists : they will probably use several OrderBooks. In addition to the fact that such behaviour can be tricky to design, it also necessitate additional information such as an investment horizon or statistics about the moments of expected returns.
This can be added in ATOM relatively easily since ATOM can produce "artificial trading days".
These artificial trading days are defined as an experimentation in which an opening period and a closing period are defined. In the middle runs the continuous double auction mechanism, while a fixing procedure governs the first price and the last price emergence. If an experiment produces many opening and periods, it implicitely produces also "trading days". One can use this ability to create multi-scales time series (with intraday prices and daily or weekly prices). Nevertheless one has to keep in mind that ATOM is grounded on a realistic continuous double auction mechanism, which means that it produces an enormous amount of information as soon as the experimentations are complex (number of agents, number of desired prices per day etc.). This should be taken into account by every experimenter designing long-running simulations.
In this section, some technical information about ATOM structure and design choices are presented. This is mainly useful for advanced users that want to have a quick overview of ATOM from a developer viewpoint.
!! Main classes: Agent, Order, Simulation, Market and OrderBook
We can identify 5 main classes in ATOM that are really important for advanced users:
* the ''Agent'' class allows the user to define its own trading strategy by specializing the {{{Agent}}} class and overriding the {{{decide}}} method,
* the ''Order'' class that provides several orders (Limit, Iceberg, Cancel ...) and enable to add new orders by extending the {{{Order}}} class and overriding its {{{execute}}} method,
* the ''Simulation'' class defines the dynamic of an experimentation. Advanced users can override its {{{queryAllAgents}}} or (use with caution) its {{{run}}} methods,
* the ''Market'' and ''OrderBook'' classes should not be changed :) but, you can shortcut the ''Simulation'' classes and send orders directly to a market or even an orderbook.
//UML diagram should be added here//
!! ATOM technical philosophy
Two main technical points have been chosen during the design of ATOM
# No doubles : all the computations are made with integer numbers. Arithmetic is never correct on any computer with doubles, thus to be sure of our results ATOM's designer has chosen to use only integer numbers. If you think prices as floating point numbers, consider them as cents ... and multiply your prices by 100. By this way we can guarantee the correctness of the results.
# No threads : Agents are not threaded for two reasons. The first one is related to the number of agents needed. For an experimentation with thousand agents it is difficult and slow to create thousand different threads. The second reason is linked to the results' reproducibility. We want to have our own scheduler to be sure to be able to reproduce exactly the same results in the same conditions. This is not possible with the default threading system. Nevertheless, there is no drawback to this choice. Notice that agents can of course decide to do nothing when they want, if you want to simulate an agent who talk twice faster than another one, just consider that the slower doesn't take any decision once of two.
# Low encapsulation. Yes it's not a good practice we know, but in ATOM core classes (Market, OrderBook, Order) some attributes are too easily accessible (public).
Let's consider the following basic example. It is proposed to show how an OrderBook actually works
In this example we will only use LimitOrder. A LimitOrder is defined with a direction (BUY or SELL), a quantity and a price.
For a "buy" order, the price is understood //at most//. For a "sell" order, the price is understood //at least//. The price of a buyer (resp. a seller) is the maximal (resp. minimal) price which is acceptable for allowing the transaction.
These orders will be called using the financial convention Bid and Ask (resp. for BUY and SELL)
The OrderBook is built in two parts : the buy/bid part and the sell/ask part. When a buy (resp. sell) order is sent to the orderbook it goes to the buy/bid (resp. sell/ask) part. You can of course have many lines in each of these lists.
|!|!quty|!price|
|Sell|...|...|
|~|...|...|
|!|!|!|
|Buy|...|...|
|~|...|...|
If a LimitOrder Bidding for 50 assets, at a maximum of 100.00 euros per asset, is sent in the buy/bid part of this OrderBook, this will deliver the following
|!|!quty|!price|
|Sell||
|!|!|!|
|Buy|50|100.00|
When a buy/bid list contains several orders, these orders are sorted in descending order. the smaller a price is, the higher its priority becomes. For example, if a second LimitOrder to buy 30 assets, at most 110.00 euros, is sent, it will be stacked at the first position.
|!|!quty|!price|
|Sell||
|!|!|!|
|Buy|30|110.00|
|~|50|100.00|
The sell/ask part uses exactly the same mechanism except that it is ordered is ascending prices. Send first a LimitOrder selling 10 assets at least 150.00, then a LimitOrder selling 20 assets at least 130.00, the second one will become the first of the sell/ask list
|!|!quty|!price|
|Sell|10|150.00|
|~|20|130.00|
|!|!|!|
|Buy|30|110.00|
|~|50|100.00|
If a buy/bid order and a sell/ask order can be matched, i.e. the max price to buy being greater or equal to the min price to sell, then a new transaction occurs and a new price is fixed. For example, if now we send a LimitOrder buying 35 assets at a limit price of 135, it will be matched with the first pending order in the ask list (20 assets available at 130, a new price is therefore fixed at 130) and the remaining quantities (i.e. the 35 - 20 = 15 assets for which a price lower than 135.00 cannot be found in the sell/ask list) will stay in the Bid list
|!|!quty|!price|
|Sell|10|150.00|
|!|!|!|
|Buy|15|135.00|
|~|30|110.00|
|~|50|100.00|
Of course, one order can match several orders at the same time. If someone sends an ask order selling 100 assets at a limit price of 100, this order will match the three remaining orders in the Buy part ... leaving 5 quantities in the ask list
|!|!quty|!price|
|Sell|10|150.00|
|~|5|100.00|
|!|!|!|
|Buy|||
In ATOM, here is the syntax used to describe all the orders previously described (see exercice1):
{{{
Order orders[] = {
new LimitOrder("AAPL","id1",LimitOrder.BID, 50, (long) 100),
new LimitOrder("AAPL","id2",LimitOrder.BID, 30, (long) 110),
new LimitOrder("AAPL","id3",LimitOrder.ASK, 10, (long) 150),
new LimitOrder("AAPL","id4",LimitOrder.ASK, 20, (long) 130),
new LimitOrder("AAPL","id5",LimitOrder.BID, 35, (long) 135),
new LimitOrder("AAPL","id6",LimitOrder.ASK, 100, (long) 100),
};
}}}
In this example, all orders are sent to the {{{AAPL}}} asset, the second parameter is an identifier that the agent can set freely. It can be used later to update or cancel the order.
![[Exercices A]]
!! Building an agent with your own trading behaviour
To define your own trading behaviour, you have to create your own agent by subclassing the {{{Agent}}} class and overriding the {{{public Order decide(String obName, Day day)}}}. Here is a simple example of an agent that send alternatively a BID or a SELL order.
{{{
import v12.*;
import v12.agents.*;
class SimpleAgent extends Agent {
public SimpleAgent(String name) {
super(name);
}
public Order decide(String obName, Day day) {
// Alterning ASK and BID orders
if (day.currentTick() % 2 == 0) {
// Logging a message in the generated log file
market.log.info("Sending an ASK order [tick="+day.currentTick()+"]");
return new LimitOrder(obName, "nop", LimitOrder.ASK, 500, (long) 14000);
}
market.log.info("Sending a BID order [tick="+day.currentTick()+"]");
return new LimitOrder(obName, "nop", LimitOrder.BID, 500, (long) 14000);
}
public static void main(String[] args) {
Simulation sim = new MonothreadedSimulation();
// Sending all logs to standard output
sim.setLogger(new Logger(System.out));
sim.addNewOrderBook("AAPL");
sim.addNewAgent(new SimpleAgent("Alan"));
sim.run(Day.createSinglePeriod(MarketPlace.CONTINUOUS, 10), 1);
sim.market.printState();
}
}
}}}
ATOM has been built to be able to run over networks. You can then distribute all the agents on several machines and even run ~HumanAgents (special agents used as interface with a human player) in a classroom if the target is to illustrate with students how a MarketPlace actually works .
If you want to do so, you will have to follow 3 steps :
* Launch the server
* Launch the agents; one command for each
* Launch the scheduler ... and begin to work !
Each of these commands can be run on any computer over the network. You can use any kind of agents, Artificial Intelligent Traders or ZIT, Human or Robots : all of these can be mixed without restriction. For example in a classroom you could need 20 ~HumanAgents, one for each students you have (1 per computer), and 20 artificial ~ZIT agents, all of these running on the same computer. Here is an example with two ~HumanAgents.
ATOM uses a server called {{{marketplace}}} listening on port 1099
!! All on the same computer
To run your first test, we will try the following network architecture on only one computer. Launch 4 shell windows (Terminals) and distribute these terminals on your screen such as you can see them without any other operation.
* Launch the server
{{{
java -cp atom.jar atom.net.Server
}}}
* Launch the agents
{{{
java -cp atom.jar atom.net.HumanModal marketplace
}}}
Launch as many agents as you want, each on one particular window (try first with 2 agents).
* launch the scheduler
{{{
java -cp atom.jar atom.net.RunOnce marketplace
}}}
!! On several computers
<html> <p><img src=atom_img/case5.png style="width: 12cm;" alt="atom artificial trading agents market"/> </html>
The procedure is exactly the same as explained previously, but you need to replace marketplace by a full network identifer of the server:
{{{rmi://machineID/marketplace}}} where {{{machineID}}} is your IP number or the full name of your computer. for example, my computer is {{{aladin.univ-lille.fr}}}
{{{
java -cp atom.jar atom.net.Server
java -cp atom.jar atom.net.HumanModal rmi://aladin.univ-lille.fr/marketplace
java -cp atom.jar atom.net.RunOnce rmi://aladin.univ-lille.fr/marketplace
}}}
Of course you will probably desire to put these lines in a command (.sh under Unix or Mac, .bat under ~MS-Windows) to avoid the burden of typing them each time.
Here are three small exercices. Knowing the list of orders to execute, will you be able to guess the final OrderBook and the price list obtained ? In order to check if your guess was right or wrong, you can type the following command line to run with ATOM such an order list.
!Exercice1
|Bid order |quty 50 |price 100 |
|Bid order |quty 30 |price 110 |
|Ask order |quty 10|price 150 |
|Ask order |quty 20|price 130 |
|Bid order |quty 35|price 135 |
|Ask order |quty 100|price 100 |
{{{
java -cp atom.jar atom.test.Exercice1
}}}
!Exercice2
|Bid order |quty 40 |price 470 |
|Ask order |quty 30 |price 500 |
|Bid order |quty 10 |price 400 |
|Ask order |quty 20 |price 520 |
|Bid order |quty 50 |price 520 |
|Ask order |quty 50 |price 380 |
{{{
java -cp atom.jar atom.test.Exercice2
}}}
!Exercice3
|Ask order |quty 15 |price 135 |
|Ask order |quty 50 |price 100 |
|Ask order |quty 30 |price 110 |
|Bid order |quty 10 |price 96 |
|Bid order |quty 25 |price 99 |
|Bid order |quty 12 |price 97 |
|Bid order |quty 70 |price 112 |
|Ask order |quty 35 |price 95 |
{{{
java -cp atom.jar atom.test.Exercice3
}}}
#Write an agent called Seller which always sends Ask orders with a random price and a random quantity.
#Write an agent called Buyer which always sends Bid orders with a random price and a random quantity.
#Write a main program which creates ans evolves 10 agents of each kind.
#Plot the curve corresponding to the price series obtained
* ''What do I need to use ATOM ?''<br/>
For a basic use of ATOM, you just need Java with a version >= 1.5 (try [[Java downloads|http://www.oracle.com/technetwork/java/javase/downloads/index.html]] and type {{{java -version}}} on a shell window to check your installed version). If you also want a graphical user interfaces, you will also need [[JFreeChart|http://www.jfree.org/jfreechart/]].
* ''On which OS can I run ATOM ?''<br/>
Since ATOM is written in Java, as soon as you have a JVM installed in your computer, you can run ATOM. The software will run on Windows, OS X or Linux.
* ''Why designers say that ATOM is an API and not a Program ?''<br/>
A program is only built for one kind of experimentation, and usually, what you need is not exactly what the designer have done. An API gives you the possibility of building all the experimentations you can desire. With an API you can develope as many specific programs as you need. Of course, ATOM is distributed with some examples of implementations, and perhaps these latter willl be sufficient for you; simply keep in mind that you can devvelope your own applications using ATOM.
* ''Is ATOM really fast ?''<br/>
ATOM is usually able to execute more than 400.000 orders ( which corresponds more or less to an entire trading day size in terms of orders sent to the Euronext system) in less than 5 secs. This benchmark has been realized with very basic agents that are not gifted with any artificial intelligence. Of course, if you involve more sophisticated agents, your experimenation will run more slowly but will remain decently fast.
* ''Are agents "mandatory" to build an experimentation ?''<br/>
Definitively no ! Agents are important if you run experimentations with specific and sophisticated behaviors or in a multi-asset environment. If not, you can send directly the orders to orderBooks. It is for example the case when you want to replay one pre-existing order-flow for example ...
* ''Why writing a program ? Why not just using the "Replay" function with my order file ?''<br/>
If you just have a few orders in an experiments, it is far easyer to create yourself a text file containing these orders and "Replay" these instructions. But if you need a large amount of complex orders in your experimental design, you will probably need agents with complex behaviors or specific configurations, and the best inthis situation is defenitely to create your own simulation script.
* ''Why can't we use floats or doubles for cash and invests ?''<br/>
It's a developer's choice. On any computer, the arithmetic is never correct with doubles, thus to be sure of the results provided by the simulations, the developers have chosen to only use integers. If you wish to express prices in a decimal way, consider the results provided in the simulations in cents and simply multiply these by 100.
* ''Can I trade several assets at the same time with ATOM ?''<br/>
Yes, this is perfectly possible ! See the Several OrderBooks section
* ''Why is there an Invest object instead of an integer to define investments ?''<br/>
Because an agent has invests for several assets/orderbooks, thus we need to use a collection-type object for this purpose. That's why the developers created Invest which an Integer object .
* ''Why the Invest object is not given in the Agent's constructor ?''<br/>
Because you can have investments on several orderbooks, not just one.
* ''Why must we close the market after each experimentation ?''<br/>
Because the files used by orderbooks are buffered. If you close the market, you also close the orderbooks, then the corresponding files in the buffer. If you do not procede to this explicit "stop", you will loose the last parts of your files
* ''What is the timestamp ?''<br/>
Just an increasing Id used to identify orders. Basically, for each order sent, this Id it is incremented. But it is also incremented when part of an iceberg is popping in the order book, thus the timestamp is always greater or equal to the number of orders sent.
* ''Why don't we use a real timestamp ?''<br/>
To sort orderbooks correctly, we need a unique Id for orders. With computers, ATOM is presently able to execute several orders during one single tick of the computer clock time. Thus, using real time to identify orders is not possible.
* ''Why do we have several prices with the same timestamp in *.prices ?''<br/>
An order with a large quantity can match several pending orders at the same time. ATOM log a price each time an order is executed.
* ''I just need Prices ! I just need orders !''<br/>
When you set your simulation, you can use a FilteredLogger which allows you to select exactly what you need in your output. Here a short example:
{{{
Simulation sim = new MonothreadedSimulation();
FilteredLogger fl = new FilteredLogger(System.out); // by default, all attributes are true
fl.orders = true; prices = true; fl.agents = false;
fl.infos = false; fl.days = false; fl.commands = false; // here we log only orders and prices
sim.setLogger(f);
...
}}}
* ''I need the returns data. How can I compute these values ?''<br/>
Use "awk" for example (see previous question) : <br>{{{awk -F';' '/Price/{if (NR==1) {anc=$3; next;} print $3-anc; anc=$3}' lvmh.atom}}}<br>Then, you just have process these data with usual statistical software.
ATOM is given with several examples, but quickly you will need to build your own experimentations, focusing on your own problems or research questions.
To run a first experimentation, you will need to import all the classes from the jar file {{{import atom.core.*;}}}. Then you have to write a small Java script. In this code, you must create an OrderBook, create a MarketPlace, add your OrderBook to this MarketPlace and send your orders to the OrderBook. As a result, you will obtain 3 files called ''lvmh.orders'' which contains the orders sent to the orderBook, ''lvmh.prices'' which contains the price series obtained with this order, and ''lvmh.mixed'' which is a temporal mix of the two previous ones.
<html> <p><img src=atom_img/case1.png style="width: 12cm;" alt="atom artificial trading agents market"/> </html>
For example, you will be able to print the resulting OrderBook or the price series (price;quantity;timestamp).
{{{
package atom.test;
import atom.core.*;
public class MyTest {
public static void main(String args[]) {
MarketPlace m = new MarketPlace();
OrderBook ob = new OrderBook("lvmh");
m.addNewOrderBook(ob);
Order orders[] = {
new LimitOrder(LimitOrder.BID, 40, (long)470 ) ,
new LimitOrder(LimitOrder.ASK, 30, (long)500 ) ,
new LimitOrder(LimitOrder.ASK, 20, (long)520 ) ,
new LimitOrder(LimitOrder.BID, 10, (long)400 ) ,
new LimitOrder(LimitOrder.BID, 50, (long)520 ) ,
new LimitOrder(LimitOrder.ASK, 50, (long)380 )
};
for (int i=0;i<orders.length;i++)
m.getOrderBook("lvmh").send(orders[i]);
m.close();
}
}
}}}
You do not have to type these commands for the moment : these are already coded in ATOM ; try the following instructions, they will run the code presented previously.
{{{
java -cp atom.jar atom.test.Exercice2
}}}
When you develop your own program, you can use many "record" procedures to track how ATOM behaves and what it actually does. You can for example decide to print the orderBook each time it is modified. This procedure will display on screen both the state of the orderBook (with the Ask and Bid parts) and the 10 last prices fixed. It can be in some cases particularly helpful to track the evolution of the orderBook after each order.
{{{
System.out.println(ob);
}}}
Many other convenient functions are available, and can be called from the orderBook, from the orders or from the agents to track what your code produces exactly. These functions "speak by themselves". For example :
{{{
System.out.println("nb fixed prices : " + ob.getNumberOfPricesFixed());
System.out.println("nb used orders : " + ob.getNumberOfOrdersReceived());
System.out.println("leaving ask size : " + ob.getNumberOfAsk());
System.out.println("leaving bid size : " + ob.getNumberOfBid());
}}}
ATOM uses its own random number generator and every agent in the system can fix a random-seed. Therefore, it is quite easy to reproduce experimentations. If you use the following line at the beginning of your main script, you will obtain exactly the same results each time you run your program.
{{{
Random.setSeed(int);
}}}
It's not really interesting in this case because we don't have any random procedure, but if you use a ZIT agent, it will become most interesting. Of course, if you use later on the ''.order'' file produced as one result of your experimentations, you will also be able to obtain exactly the same result. Two different ways to fix and reproduce an experimentation are therefore provided in ATOM (use the random-seed or the ".orders" file).
Taking all these remarks into account, the previous program could also be written like the following :
{{{
package atom.test;
import atom.core.*;
public class MyTest {
public static void main(String args[]) {
Random.setSeed(1000);
MarketPlace m = new MarketPlace();
OrderBook ob = new OrderBook("lvmh");
m.addNewOrderBook(ob);
Order orders[] = {
new LimitOrder(LimitOrder.BID, 40, (long)470 ) ,
new LimitOrder(LimitOrder.ASK, 30, (long)500 ) ,
new LimitOrder(LimitOrder.ASK, 20, (long)520 ) ,
new LimitOrder(LimitOrder.BID, 10, (long)400 ) ,
new LimitOrder(LimitOrder.BID, 50, (long)520 ) ,
new LimitOrder(LimitOrder.ASK, 50, (long)380 )
};
for (int i=0;i<orders.length;i++) {
m.getOrderBook("lvmh").send(orders[i]);
System.out.println(ob);
}
System.out.println("nb fixed prices : " + ob.getNumberOfPricesFixed());
System.out.println("leaving ask size : " + ob.getNumberOfAsk());
System.out.println("leaving bid size : " + ob.getNumberOfBid());
m.close();
}
}
}}}
Many experimentations are provided with the ATOM package. Two of these experimentations are frequently used. The first one allows to create time series of prices or orders, the second allows to replay an order flow. These two classes are most of the time sufficient for a large number of experimentations and learnings.
<html> <p><img src="atom_img/case4.png" style="width: 12cm;align:center" alt="atom artificial trading agents market"/> </html>
You can also try these functionnalities [[directly on the web|http://atom.iut-info.univ-lille.fr/simu/]] !
!!Generate
If you need to generate a price series or an order list, the following command can be used :
{{{
java -cp atom.jar v12.Generate 10 1 1000
}}}
The first parameter is the number of ZIT agents, the second parameter the number of orderbooks and the third and last parameters is the number of round of talk. So in this example, 10 ZIT agents send orders randomly generated to one orderbook 1000 times. The complete execution trace is send to the standard output. If you are running a UNIX system, you can easily redirect this outpur to a file with the following command:
{{{
java -cp atom.jar v12.Generate 10 1 1000 > ExampleFile.orders
}}}
If you prefer working in a graphical environment, you can simply use this command: {{{java -cp atom.jar v12.Generate}}}
<html> <p><img src="atom_img/GenerateGUI.png" style="width: 12cm;align:center" alt="generate command in gui mode"/> </html>
!!Replay
The {{{Replay}}} command enables to replay a given order file. If there are prices within the order file, they are skipped and re-generated thanks to the sequential execution of orders. The following command shows how to replay the file {{{ExampleFile.orders}}}:
{{{
java -cp atom.jar v12.Replay ExampleFile.orders
}}}
Of course, if you have launched the previous command to generate your orders file, the resulting prices file obtained will be exactly the same as the previous one. Test these commands :
{{{
1> java -cp atom.jar v12.Generate 10 1 1000 > InitialFile.orders
2> java -cp atom.jar v12.Replay InitialFile.orders ReplayedFile.orders
3> diff InitialFile.orders ReplayedFile.orders
}}}
Pay attention to the fact that the two price files are strictly identical. Indeed, {{{Replay}}} is a multi-agent replayer so all agents present within the order file are re-created and iniitialized with their orders.
If you prefer working in a graphical environment, you can simply use this command: {{{java -cp atom.jar v12.Replay}}}
<html> <p><img src="atom_img/ReplayGUI.png" style="width: 12cm;align:center" alt="replay command in gui mode"/> </html>
Each time you run ATOM, the platform creates an execution record constituted of one file containing all orders and prices generated during the simulation.
To ease the manipulation of this file in a spreadsheet or statistical software, the format used is a simple CSV.
For the next section, we consider that you have run the following command to obtain the log file.
{{{
java -cp atom.jar v12.test.TestGeneratedFile
}}}
You should obtain a file named {{{test.atom}}} in the current directory. Have a look at his content:
{{{
1$ cat test.atom
Order;IBM;zit_3;1;L;A;14347;33;-1
Order;GOOG;zit_3;2;L;A;14708;40;-1
Order;AAPL;zit_3;3;L;B;14594;40;-1
Order;IBM;zit_2;1;L;B;14765;87;-1
Price;IBM;14347;33;B;zit_3-1;zit_2-1;14347;14765
Agent;zit_2;-463451;IBM;33;14347
Agent;zit_3;483451;IBM;-33;14347
Order;GOOG;zit_2;2;L;A;14886;24;-1
Order;AAPL;zit_2;3;L;B;14228;61;-1
Order;IBM;zit_1;1;L;B;14325;32;-1
Order;GOOG;zit_1;2;L;A;14535;13;-1
Order;AAPL;zit_1;3;L;B;14892;63;-1
Tick;1;IBM;0;14765;14347;
Tick;1;GOOG;14886;0;0;
Tick;1;AAPL;0;14892;0;
Order;IBM;zit_2;4;L;B;14759;44;-1
(...)
Order;AAPL;zit_2;30;L;B;14930;78;-1
Price;AAPL;14221;11;B;zit_1-27;zit_2-30;14221;14930
Agent;zit_2;-5994571;AAPL;73;14221
Agent;zit_1;3960817;AAPL;-74;14221
Price;AAPL;14284;29;B;zit_3-21;zit_2-30;14284;14930
Agent;zit_2;-6408807;AAPL;102;14284
Agent;zit_3;2477990;AAPL;-28;14284
Price;AAPL;14357;38;B;zit_1-24;zit_2-30;14357;14930
Agent;zit_2;-6954373;AAPL;140;14357
Agent;zit_1;4506383;AAPL;-112;14357
Tick;5;IBM;14725;14381;14725;
Tick;5;GOOG;14795;14247;14333;
Tick;5;AAPL;14905;14034;14357;
Day;2;IBM;14725;14109;14725;14725;12;
Day;2;GOOG;14218;14006;14742;14333;10;
Day;2;AAPL;14427;14146;14978;14357;10;
}}}
As you can see, there are several kinds of traces: orders, prices, agents, execs, ticks and days. Let's try to understand what these lines mean.
!! Order trace
{{{
Order;GOOG;zit_3;2;L;B;14335;41;-1
}}}
Here is a detailed description of all the elements of an order log:
# type of the current line. Here, it is an order line,
# OrderBook name, ie. the asset's name,
# order identifier, it used later in this example to cancel this order,
# nature of this order (L=LimitOrder, C=CancelOrder, I=IcebergOrder, M=MarketOrder, U=UpdateOrder),
# order direction A=ASK (selling) and B=BUY (buying),
# price that the user choose to buy or sell,
# quantity that the user choose to buy or sell,
# order validity.
!! Agent trace
{{{
Agent;zit_2;-6954373;AAPL;140;14357
}}}
Here is a detailed description of all the elements of an agent log:
# type of the current line. Here, it is an agent line,
# the agent name,
# the agent cash,
# the state of the asset that has been modified (asset name, quantity, current price)
!! Price trace
{{{
Price;AAPL;14198;57;A;zit_1-3;zit_2-3;14002;14198
}}}
Here is a detailed description of all the elements of a price log:
# type of the current line. Here, it is a price line,
# OrderBook name that has fixed this price,
# price that has been generated,
# quantity that has been exchanged,
# direction that has generated this price,
# order identifier of the order initiating the price,
# order identifier of the order fulfilling the other order,
# the current best ask price,
# the current best bid price,
!! Tick trace
{{{
Tick;1;IBM;0;14765;14347;
Tick;1;GOOG;14886;0;0;
Tick;1;AAPL;0;14892;0;
}}}
Here is a detailed description of all the elements of a tick log:
# type of the current line: here, it is an tick line,
# tick number (here the 10th one of this period),
# an asset with its current state: asset's name, best ask price, best bid price and last fixed price.
!! Day trace
{{{
Day;2;IBM;14725;14109;14725;14725;12;
Day;2;GOOG;14218;14006;14742;14333;10;
Day;2;AAPL;14427;14146;14978;14357;10;
}}}
The day log is similar to the tick log:
# type of the current line: here, it is an day line,
# day number (here the third day),
# an asset with its current state: asset's name, last fixed price and the number of fixed prices.
ATOM developped with a main idea : it must run fast and make experimentation design easy. For these reasons, the graphical user interface (GUI) is not included in the main module. To run fast, one must run programs in a shell ... notice that ATOM is able to execute a real world order flow from the Euronext Stock Exchange in a few seconds.
Nevertheless, a GUI is provided with ATOM, even if it is absolutely not mandatory to run it "in general". You may want to use this GUI in a centralized experiment, or in a distributed one. For example, using ATOM in a classroom is much more "user friendly" with the graphical interface.
Thus, a GUI for the server part is provided, and a GUI for HumanAgent players as well.
To be able to use these GUIs, you must have installed [[JFreeChart|http://www.jfree.org/jfreechart/]] and have in your CLASSPATH the files jcommon-1.0.15.jar and jfreechart-1.0.12.jar
{{{
export CLASSPATH=atom.jar:jcommon-1.0.15.jar:jfreechart-1.0.12.jar
}}}
* Launch the server
{{{
java atom.net.GraphicalServer
}}}
* Launch as many agents as you want, each on one particular window (try first with 2 agents).
{{{
java atom.net.GraphicalHumanModal marketplace
or
java atom.net.ZIT marketplace
}}}
Then press the "start" button on the GUI
Here is what you should see with a Server, two ZIT agents without any GUI, and a Human Player and its own GUI.
<html> <img src=atom_img/atom2.jpg style="width: 20cm;" alt="atom artificial trading agents market"/> </html>
Several classes have their equivalent with GUI :
* MarketPlace -> GraphicalMarketPlace
* HumanModalAgent -> GraphicalHumanModalAgent
* HumanNotModalAgent -> GraphicalHumanNotModalAgent
So, basically, if you want to see a classical experimentation with a GUI you can replace MarketPlace by GraphicalMarketPlace and see this picture during your experimentation :
[img[atom_img/atom.jpg]]
Remember : it will run really fast ... if you want to see something in the [[Speed Up]] previous experimentation for example, don't forget to put some {{{ try{sleep(5000)} catch(Exception e){} }}} between your orders or you will not be able to distinguish anything on your screen.
What is an agent in ATOM ? An agent is just an actor of the MarketPlace endowed with cash and investments. Trading on the market will modify these characteristics. A classical Agent has no behavior. It executes the actions you provide him with and will evolve during the market activity in terms of holdings. Thus, the main difference between sending directly orders to the market and sending orders from agents is mainly a matter of speed. Without agents, you will go faster, with agents you can track their portfolio evolution (<hich is not the case in the first situation). It depends on your research targets. If you just study market dynamics (such as price motions), you do not need agents; on the contrary, you may be interested in the evolution of agents' portfolios and will need to use them.
<html> <p><img src=atom_img/case2.png style="width: 12cm;" alt="atom artificial trading agents market"/> </html>
The most trivial Agent existing in ATOM is call {{{Agent}}}. To create this agent, you just have to say how its portfolio is composed (cash + investments). Once it has been created and added to the MarketPlace, you can ask this agent to send orders. In the following example, agents receive 100 assets and 1000 currency units.
{{{
package atom.test;
import atom.core.*;
public class TestSchoolCaseWithAgents {
public static void main(String args[]) {
MarketPlaceItf m = new MarketPlace();
OrderBook ob = new OrderBook("lvmh");
m.addNewOrderBook(ob);
Agent a1 = new Agent("philippe", 50000);
a1.setInvestment("lvmh", 1000);
Agent a2 = new Agent("olivier", 50000);
a2.setInvestment("lvmh", 1000);
m.addNewAgent(a1);
m.addNewAgent(a2);
Order orders[] = {
new LimitOrder(LimitOrder.BID, 40, (long)470 ) ,
new LimitOrder(LimitOrder.ASK, 30, (long)500 ) ,
new LimitOrder(LimitOrder.BID, 10, (long)400 ) ,
new LimitOrder(LimitOrder.ASK, 20, (long)520 ) ,
new LimitOrder(LimitOrder.BID, 50, (long)520 ) ,
new LimitOrder(LimitOrder.ASK, 50, (long)380 )
};
for (int i=0;i<orders.length;i++)
if (i%2==0) a1.send("lvmh",orders[i]);
else a2.send("lvmh",orders[i]);
System.out.println("nb fixed prices : "+ob.getNumberOfPricesFixed());
System.out.println("leaving ask size : "+ob.getNumberOfAsk());
System.out.println("leaving bid size : "+ob.getNumberOfBid());
System.out.println(a1);
System.out.println(a2);
m.close();
}
}
}}}
At the end of this execution, you can see in ''lvmh.prices'' that four prices have been fixed :
|price|quty|type|timestamp|
| 500 | 30 | B | 5 |
| 520 | 20 | B | 5 |
| 470 | 40 | A | 6 |
| 400 | 10 | A | 6 |
and you can see that philippe has only 1800 cash but with 1100 assets {{{phil(1800 {lvmh=1100})}}}, instead olivier has 98200 cash and 900 assets {{{oliv(98200 {lvmh=900})}}}. If you have a look to in ''lvmh.orders'' you will have information on the evolution of agent's portfolios associated to the agent's name.
!! Les agents basés sur un algorithme d'apprentissage
Un {{{LcsAgent}}} est un agent qui repose sur une politique de fixation de prix et de quantité et qui exploite un mécanisme d'apprentissage basé sur un //Learning Classifier System// qui permet de déterminer la direction du prochain ordre.
Lorsque l'agent LCS est sollicité, il détermine dans un premier temps la variation de prix depuis sa dernière sollicitation, ce qui permet de définir la récompense utilisée ensuite dans le mécanisme de renforcement. Ensuite, l'agent utilise son classifieur pour déterminer la direction du prochain ordre avant de déléguer la création de l'ordre aux politiques de fixation de prix et de quantité.
!! Comment fonctionne le LCS
Chaque LCS possède un ensemble de descripteurs qui effectuent des tests sur l'environnement. A un instant {{{t}}}, certains de ces descripteurs sont vérifiés et d'autres non, fournissant ainsi une description de la situation actuelle. Le LCS possède ensuite un ensemble de règles permettant la prise de décision (direction dans notre cas).
Les règles sont des triplets (//trits//, direction, score) où le //trits// correspond à l'identification du déclenchement d'un ensemble de
descripteurs, la direction peut prendre les valeurs {{{ASK, BID, HOLD}}}, et le score est une valeur entière représentant la pertinence de cette règle. Cette pertinence est basée sur le fait qu'une règle prescrivant un ordre d'achat sera renforcée si le prix du titre monte au prochain tour (et réciproquement, un ordre de vente sera renforcé si le prix descend).
Trois étapes sont mises en oeuvre :
# la procédure de renforcement reposant sur l'analyse de ce qui s'est passé et permet de récompenser les règles qui font une bonne prédiction et pénaliser les règles qui en font une mauvaise. Ainsi, les règles déclenchables prescrivant un achat seront renforcées (+1 à leur score) si le prix a augmenté (et réciproquement pour les règles prescrivant une vente).
# l'algorithme génétique, qui enlève les scores les plus faibles ou les règles très peu activées, et complète l'ensemble par mutation et //crossing-over// des meilleures.
# La prise de décision, qui permet de décider en fonction de l'état actuel de la direction de l'ordre futur
Une fois fait, c'est la politique qui complète le prix et la quantité avant d'envoyer l'ordre effectif.
A LimitOrder is an order defined with a price and a quantity. For a buy order the price is understood //at most//. For a sell order, the price is understood //at least//.
!! Order driven financial markets
ATOM is an implementation of an order driven financial market like EuroNEXT/NYSE. These markets rely on the exchange of orders that are automatically matched against each others through double auction books. Thus, an order-driven market involves traders that send orders to a market, a market that gathers several double auction orderbooks, one per asset traded on the market. Since the advent and fast development of electronic markets, order-driven markets have offered more and more orders types even if the most current are market orders (buy/sell at the current price), limit order (buy/sell at a given price) and cancel order (to retract an order that has not yet been matched). Below, you'll find the description of all order-driven markets concepts in ATOM that are made available as simple classes that one can use to fit its needs.
!! ATOM main concepts
* A MarketPlace is a set of OrderBook. Each agent must be listed in a MarketPlace to be able to trade. Usually in ATOM, you have one MarketPlace containing several OrderBook and Agent.
* An OrderBook is an object that receive orders and fix prices. Each time a human being or an artificial agent sends an order, the OrderBook records it and try to execute it. This latter operation delivers a price. If the new order cannot be matched with pending orders it is kept "as is", waiting for a counterpart. In ATOM you can have several OrderBook running simultaneously, which allows to build arbitragist agents, speculators who seek to take advantage of price differences on various assets.
* An [[Order]] represent an offer to sell or buy an asset. In ATOM several kind of orders can be used: LimitOrders, MarketOrders, CancelOrders, UpdateOrders and many others (see [[EURONEXT RULE BOOK 2009|ruleBook.pdf]] for a detailed description of each order). Agents, both artificial or human beings, can send orders to a MarketPlace. To emit an order you just have to use the appropriate order class and fulfil the associate constructor.
* An [[Agent]] represent an entity that sends orders to any OrderBook of the MarketPlace. Agent can receive a behaviour or not, depending upon the level of sophistication the experimenter wants to have in his system. If the agent does not have any behaviour, it will just be able to send orders that have been defined elsewhere in the system (it could simply be a real-world order flow for example). If the Agent have a behaviour, it will be able to manage itself the orders, send them to the MarketPlace and let these orders evolve in the simulation. In that last case (agents gifted with a specific behaviour), frequently, the market will ask all agents whether they want to send an order or not.
* A [[Simulation]] is made of a market, an agents set and the definition of a trading day. The simulation is provided to ease the building of financial market simulation and handles execution issues like threading (two kind of execution can be done with ATOM: mono or multi-threaded evaluation).
Principles
[[What is ATOM ?]]
[[Main concepts]]
[[Use cases]]
[[Basic Example]]
[[F.A.Q.]]<<tiddler ToggleRightSidebar with: ... tooltip>>
Using ATOM
[[Quick Start]]
[[Generate and Replay]]
[[Generated Files]]
[[Analyze Results]]
Coding yourself
[[ZIT intra/extra-day]]
[[Build your own agent]]
[[Strategic agents]]
[[Learning agents]]
[[Trader evaluation]]
Inside ATOM
[[Architecture]]
MarketPlace. A MarketPlace is just a set of orderBooks. Each agent must be listed on a Market. Usually in ATOM, you have one Market containing several orderBooks and Agents.
[[First Code]]
[[Involving Agents]]
[[Speed Up]]
[[Agents Behavior]]
[[Several OrderBooks]]
[[Arbitraging]]
[[Distributed Environment]]
[[Graphical Interface]]
[[Using Eclipse]]
The OrderBook is the object able to receive orders and to fix prices. Each time a human or an artificial agent sends an order, the orderbook records it and try to execute it. This latter operation delivers a price. If the new order cannot be matched with pending orders it is kept "as is", waiting for a counterpart. In ATOM you can have several OrderBooks running simultaneously allowing to build arbitragist agents, speculators who seek to take advantage of price differences in various assets.
ATOM is written in the Java language. First of all, verify that Java is already installed in your computer: {{{java -version}}}
If you obtain an error, please install JAVA from [[ORACLE website|http://www.oracle.com/technetwork/java/javase/downloads/index.html]]
If you need help to code in Java please have a look to the [[Java Tutorial|http://docs.oracle.com/javase/tutorial/]] from ORACLE or the [[Thinking In Java|http://www.mindview.net/Books/TIJ/]] book.
The ATOM core package is given in the jar file {{{atom.jar}}}. Verify that you have it.
You don't have to install anything. ATOM is given as a jar file, you don't have to compile or uncompress it. Just leave it as it is :)
!! Test a pre-build class
Now, you are able to run experimentations that have been coded previously, or design your own experimentations. The following code will run 10 basic agents during 1000 fixed prices with one OrderBook. Launch a shell window and type the following line :
{{{
java -cp atom.jar v12.Generate 10 1 1000
}}}
Try this ... several times, changing the values. You must see a complete trace of generated orders and prices on your standard output.
But you can also use the CLASSPATH variable from your OS and then shorten the command line:
* for Unix,Linux,~MacOs: {{{export CLASSPATH=.:atom.jar}}}
* for Windows: {{{set CLASSPATH=.;atom.jar}}}
You can then launch your experimentations in this simplified way: {{{java v12.Generate 10 1 1000}}}
!! Compile and Run your own program
Put in the same directory {{{atom.jar}}} and your JAVA main experimentation, called for example {{{Test.java}}}
To compile : {{{javac -cp atom.jar Test.java}}}
To run : {{{java -cp atom.jar:. Test}}}
Like previously, if your CLASSPATH has been well configured, the commands will avoid the {{{-cp}}} options and become shorter.
{{{
package v12.test;
import v12.*;
import v12.agents.*;
public class WikiUseCase1 {
public static void main(String[] args) {
final String APPLE = "AAPL";
MarketPlace market = new MarketPlace();
// Orderbook creation to represent the Apple asset
market.orderBooks.put(APPLE, new OrderBook(APPLE));
// We need an agent to keep track of assets evolution
DumbAgent agent = new DumbAgent("dumb");
// First, we want to sell 1000 Apple assets at 350.00 euros
market.send(agent, new LimitOrder(APPLE, "order1", LimitOrder.ASK, 1000, (long) 35000));
// No matching order yet, so the order wait within the orderbook
// A new order is created to buy 500 Apple assets at the current market
// price
market.send(agent, new MarketOrder(APPLE, "order2", LimitOrder.BID, 500));
// The remaining part of the first order is still waiting in the order book
System.out.println("Market state:");
market.printState();
}
}
}}}
{{{
package v12.test;
import v12.*;
import v12.agents.*;
import java.util.*;
public class WikiUseCase2 {
public static void main(String[] args) {
final String APPLE = "AAPL";
List<Order> orders1 = new ArrayList<Order>();
for (int i=0; i <5; i++) {
orders1.add(new LimitOrder(APPLE, "order1", LimitOrder.ASK, 500, (long) 30000+1000*i));
}
Agent seller = new Automata("seller", orders1, true);
List<Order> orders2 = new ArrayList<Order>();
for (int i=0; i <5; i++) {
orders2.add(new LimitOrder(APPLE, "order1", LimitOrder.BID, 500, (long) 35000-1000*i));
}
Agent buyer = new Automata("buyer", orders2, true);
Simulation sim = new MonothreadedSimulation();
// Let's see what is happenning when the simulation is running
sim.setLogger(new Logger(System.out));
// Orderbook creation to represent the Apple asset
sim.addNewOrderBook(APPLE);
// Adding agent to the simulation
sim.addNewAgent(seller);
sim.addNewAgent(buyer);
// Let's launch the simulation
sim.run(Day.createSinglePeriod(MarketPlace.CONTINUOUS, 5), 1);
// Final market state
sim.market.printState();
}
}
}}}
As mentionned before, one of the most interesting advantages of the ATOM package is its ability to run several orderBooks (one for each asset) simultaneously. Such experimentations are not much more complicated to design than the simplest ones where only one order book is involved. Each time a new orderBook is created, each agent in the market is granted to use it. Similarly, each new agent appearing in the market can use all the existing orderBooks. ATOM doesn't take care in which order agents and orderbooks are created. You can of course control for such an order if required, and even in a dynamic fashion if you fancy doing so. Here is a limited example with ZIT agents.
{{{
public class TestSeveralOrderBooks
{
public static void main(String args[])
{
MarketPlace m = new MarketPlace();
// create n order books
OrderBook[] obs = new OrderBook[3];
for (int i = 0; i < obs.length; i++)
{
obs[i] = new OrderBook("lvmh" + (i + 1));
m.addNewOrderBook(obs[i]);
}
// create n agents
Agent[] as = new Agent[10];
for (int i = 1; i < as.length; i++)
{
as[i] = new ZIT0("agent_" + i, 100000);
// they have different investments on each orderBook
for (int j = 0; j < obs.length; j++)
as[i].setInvestment(obs[j].getName(), new Invest((j + 1) * 1000));
m.addNewAgent(as[i]);
}
// Note that you can create, or add agents and orderbooks in any order
for (int i = 1; i <= 100; i++)
{
m.runOnce();
}
// results
for (int i = 0; i < obs.length; i++)
{
System.out.println("nb fixed prices : " + obs[i].getNumberOfHistory());
System.out.println("leaving ask size : " + obs[i].getNumberOfAsk());
System.out.println("leaving bid size : " + obs[i].getNumberOfBid());
System.out.println("\n");
}
m.close();
}
}
}}}
/***
|Name|SinglePageModePlugin|
|Source|http://www.TiddlyTools.com/#SinglePageModePlugin|
|Documentation|http://www.TiddlyTools.com/#SinglePageModePluginInfo|
|Version|2.9.6|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|Show tiddlers one at a time with automatic permalink, or always open tiddlers at top/bottom of page.|
This plugin allows you to configure TiddlyWiki to navigate more like a traditional multipage web site with only one tiddler displayed at a time.
!!!!!Documentation
>see [[SinglePageModePluginInfo]]
!!!!!Configuration
<<<
<<option chkSinglePageMode>> Display one tiddler at a time
><<option chkSinglePagePermalink>> Automatically permalink current tiddler
><<option chkSinglePageKeepFoldedTiddlers>> Don't close tiddlers that are folded
><<option chkSinglePageKeepEditedTiddlers>> Don't close tiddlers that are being edited
<<option chkTopOfPageMode>> Open tiddlers at the top of the page
<<option chkBottomOfPageMode>> Open tiddlers at the bottom of the page
<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed)
Notes:
* The "display one tiddler at a time" option can also be //temporarily// set/reset by including a 'paramifier' in the document URL: {{{#SPM:true}}} or {{{#SPM:false}}}.
* If more than one display mode is selected, 'one at a time' display takes precedence over both 'top' and 'bottom' settings, and if 'one at a time' setting is not used, 'top of page' takes precedence over 'bottom of page'.
* When using Apple's Safari browser, automatically setting the permalink causes an error and is disabled.
<<<
!!!!!Revisions
<<<
2008.10.17 [2.9.6] changed chkSinglePageAutoScroll default to false
| Please see [[SinglePageModePluginInfo]] for previous revision details |
2005.08.15 [1.0.0] Initial Release. Support for BACK/FORWARD buttons adapted from code developed by Clint Checketts.
<<<
!!!!!Code
***/
//{{{
version.extensions.SinglePageModePlugin= {major: 2, minor: 9, revision: 6, date: new Date(2008,10,17)};
//}}}
//{{{
config.paramifiers.SPM = { onstart: function(v) {
config.options.chkSinglePageMode=eval(v);
if (config.options.chkSinglePageMode && config.options.chkSinglePagePermalink && !config.browser.isSafari) {
config.lastURL = window.location.hash;
if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
}
} };
//}}}
//{{{
if (config.options.chkSinglePageMode==undefined)
config.options.chkSinglePageMode=false;
if (config.options.chkSinglePagePermalink==undefined)
config.options.chkSinglePagePermalink=true;
if (config.options.chkSinglePageKeepFoldedTiddlers==undefined)
config.options.chkSinglePageKeepFoldedTiddlers=false;
if (config.options.chkSinglePageKeepEditedTiddlers==undefined)
config.options.chkSinglePageKeepEditedTiddlers=false;
if (config.options.chkTopOfPageMode==undefined)
config.options.chkTopOfPageMode=false;
if (config.options.chkBottomOfPageMode==undefined)
config.options.chkBottomOfPageMode=false;
if (config.options.chkSinglePageAutoScroll==undefined)
config.options.chkSinglePageAutoScroll=false;
//}}}
//{{{
config.SPMTimer = 0;
config.lastURL = window.location.hash;
function checkLastURL()
{
if (!config.options.chkSinglePageMode)
{ window.clearInterval(config.SPMTimer); config.SPMTimer=0; return; }
if (config.lastURL == window.location.hash) return; // no change in hash
var tids=decodeURIComponent(window.location.hash.substr(1)).readBracketedList();
if (tids.length==1) // permalink (single tiddler in URL)
story.displayTiddler(null,tids[0]);
else { // restore permaview or default view
config.lastURL = window.location.hash;
if (!tids.length) tids=store.getTiddlerText("DefaultTiddlers").readBracketedList();
story.closeAllTiddlers();
story.displayTiddlers(null,tids);
}
}
if (Story.prototype.SPM_coreDisplayTiddler==undefined)
Story.prototype.SPM_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler,template,animate,slowly)
{
var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
var tiddlerElem=document.getElementById(story.idPrefix+title); // ==null unless tiddler is already displayed
var opt=config.options;
var single=opt.chkSinglePageMode && !startingUp;
var top=opt.chkTopOfPageMode && !startingUp;
var bottom=opt.chkBottomOfPageMode && !startingUp;
if (single) {
story.forEachTiddler(function(tid,elem) {
// skip current tiddler and, optionally, tiddlers that are folded.
if ( tid==title
|| (opt.chkSinglePageKeepFoldedTiddlers && elem.getAttribute("folded")=="true"))
return;
// if a tiddler is being edited, ask before closing
if (elem.getAttribute("dirty")=="true") {
if (opt.chkSinglePageKeepEditedTiddlers) return;
// if tiddler to be displayed is already shown, then leave active tiddler editor as is
// (occurs when switching between view and edit modes)
if (tiddlerElem) return;
// otherwise, ask for permission
var msg="'"+tid+"' is currently being edited.\n\n";
msg+="Press OK to save and close this tiddler\nor press Cancel to leave it opened";
if (!confirm(msg)) return; else story.saveTiddler(tid);
}
story.closeTiddler(tid);
});
}
else if (top)
arguments[0]=null;
else if (bottom)
arguments[0]="bottom";
if (single && opt.chkSinglePagePermalink && !config.browser.isSafari) {
window.location.hash = encodeURIComponent(String.encodeTiddlyLink(title));
config.lastURL = window.location.hash;
document.title = wikifyPlain("SiteTitle") + " - " + title;
if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
}
if (tiddlerElem && tiddlerElem.getAttribute("dirty")=="true") { // editing... move tiddler without re-rendering
var isTopTiddler=(tiddlerElem.previousSibling==null);
if (!isTopTiddler && (single || top))
tiddlerElem.parentNode.insertBefore(tiddlerElem,tiddlerElem.parentNode.firstChild);
else if (bottom)
tiddlerElem.parentNode.insertBefore(tiddlerElem,null);
else this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
} else
this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
var tiddlerElem=document.getElementById(story.idPrefix+title);
if (tiddlerElem&&opt.chkSinglePageAutoScroll) {
// scroll to top of page or top of tiddler
var isTopTiddler=(tiddlerElem.previousSibling==null);
var yPos=isTopTiddler?0:ensureVisible(tiddlerElem);
// if animating, defer scroll until after animation completes
var delay=opt.chkAnimate?config.animDuration+10:0;
setTimeout("window.scrollTo(0,"+yPos+")",delay);
}
}
if (Story.prototype.SPM_coreDisplayTiddlers==undefined)
Story.prototype.SPM_coreDisplayTiddlers=Story.prototype.displayTiddlers;
Story.prototype.displayTiddlers = function() {
// suspend single/top/bottom modes when showing multiple tiddlers
var opt=config.options;
var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
this.SPM_coreDisplayTiddlers.apply(this,arguments);
opt.chkBottomOfPageMode=saveBPM;
opt.chkTopOfPageMode=saveTPM;
opt.chkSinglePageMode=saveSPM;
}
//}}}
ATOM is able to run really fast. It is for example able to execute 400.000 orders in less than 5 seconds with a basic computer.
This example is geared at filling each part of the OrderBook with five orders and then at sending 10 orders to match the existing pending orders in the OrderBook. It repeats this operation 20.000 times, thus 400.000 orders are sent. At the end, the OrderBook is empty.
{{{
public class TestLargeScale
{
public static void main(String args[])
{
long timebefore = System.currentTimeMillis();
OrderBook ob = new OrderBook("lvmh");
MarketPlace m = new MarketPlace();
m.addNewOrderBook(ob);
for (int x = 1; x <= 20000; x++)
{
for (int i = 10; i >= 6; i--)
ob.send( new LimitOrder(LimitOrder.ASK, 10, i) );
for (int i = 5; i >= 1; i--)
ob.send( new LimitOrder(LimitOrder.BID, 10, i) );
for (int i = 5; i >= 1; i--)
ob.send( new LimitOrder(LimitOrder.ASK, 10, i) );
for (int i = 6; i <= 10; i++)
ob.send( new LimitOrder(LimitOrder.BID, 10, i) );
}
long timeafter = System.currentTimeMillis();
System.out.println("Time : " + (timeafter - timebefore) + " sec");
System.out.println("ask : " + ob.getNumberOfAsk());
System.out.println("bid : " + ob.getNumberOfBid());
System.out.println("orders : " + ob.getNumberOfOrdersReceived());
System.out.println("prices : " + ob.getNumberOfPricesFixed());
m.close();
}
}
}}}
You can test this program using the following command directly from your Terminal Window:
{{{
java -cp atom.jar atom.test.TestLargeScale
}}}
!! Strategic agents : building complex trading behaviours
A ''~StrategicAgent'' in ATOM is an agent whose behaviour is organized around three concepts:
* a ''Signal'', that generates a direction (BUY/HOLD/SELL) in function of the current market state,
* a ''Strategy'', that aggregates a set of signals into one resulting signal,
* a ''Policy'', that defines the number of assets (volume) and the price for the next order.
This separation of concerns enable to provide some building blocks for each entity that can be composed to produced several behaviours.
Here are the available signals (interface {{{v12.agents.chartist.signal.Signal}}}):
* ''~RandomDirection''(double holdProbability): returns randomly HOLD, BUY or SELL,
* ''Periodic''(int nBuy, int Sell): cycles on {{{nBuy}}} BUY then {{{nSell}}} SELL infinitely,
* ''Variation''(int nbUp, int nbDown, int n): count the number of successive variations of the sum of {{{n}}} last prices, if above a certain value BUY else SELL,
* ''~MovingAverage''(int n): compare current price to the average of last {{{n}}} prices, if current price is above this average then BUY else SELL,
* ''Momentum''(int n, double threshold): compute {{{(currentPrice-previousPrice_n)}}} if greater than previous momentum (with {{{threshold}}}) then BUY else SELL,
* ''~MixedMovingAverage''(int n1, int n2, double threshold): compute the average of last n1 prices (short average) with the average of last n2 prices (long average), if {{{short average > long average}}} (with {{{threshold}}}) then BUY else SELL.
Here are the two strategies available {{{v12.agents.chartist.strategy.Strategy}}}:
* ''~SingleSignalStrategy''(boolean regular): that use only one signal but can inverse it if needed (depending on {{{regular}}} value),
* ''Majority'': that returns the direction that have the majority among signals or HOLD in case of equality.
Finally, the available policies (interface {{{v12.agents.chartist.policy.Policy}}}) for quantity and price determination (direction is fixed by the Strategy) are:
* ''~RandomPolicy''(int minQuant,int maxQuant,long minPrice,long maxPrice): chooses randomly between some bounds the quantity and price for an order,
* ''~LastPrice''(long defaultPrice, int quantity, double rate, boolean strictlyBest): uses the last price with a fixed quantity,
* ''~MarketOrderPolicy''(long defaultPrice, int quantity, boolean bestLimit): uses a fixed quantity and choose the price from the bid-ask spread if {{{bestlimit}}} is true or the worst one (beware it's a {{{LimitOrder}}} that is sent not a {{{MarketOrder}}}),
* ''~BestBidAskPolicy''(long defaultPrice, int quantity, double rate, boolean strictlyBest): uses a fixed quantity and defines the price in order to be within the bi-ask spread (strictly the best or equals to the best current offer in function of {{{strictlyBest}}}.
You can generate a list with 35 different agents by calling the {{{StrategicAgent.getSoup()}}} method.
.title {color:#f00; font-style: italic;}
/%
!info
|Name|ToggleRightSidebar|
|Source|http://www.TiddlyTools.com/#ToggleRightSidebar|
|Version|2.0.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|transclusion|
|Description|show/hide right sidebar (SideBarOptions)|
Usage
<<<
{{{
<<tiddler ToggleRightSidebar>>
<<tiddler ToggleRightSidebar with: label tooltip>>
}}}
Try it: <<tiddler ToggleRightSidebar##show
with: {{config.options.chkShowRightSidebar?'►':'◄'}}>>
<<<
Configuration:
<<<
{{{
config.options.chkShowRightSidebar (true)
config.options.txtToggleRightSideBarLabelShow (◄)
config.options.txtToggleRightSideBarLabelHide (►)
}}}
<<<
!end
!show
<<tiddler {{
var co=config.options;
if (co.chkShowRightSidebar===undefined) co.chkShowRightSidebar=true;
var sb=document.getElementById('sidebar');
var da=document.getElementById('displayArea');
if (sb) {
sb.style.display=co.chkShowRightSidebar?'block':'none';
da.style.marginRight=co.chkShowRightSidebar?'':'1em';
}
'';}}>><html><nowiki><a href='javascript:;' title="$2"
onmouseover="
this.href='javascript:void(eval(decodeURIComponent(%22(function(){try{('
+encodeURIComponent(encodeURIComponent(this.onclick))
+')()}catch(e){alert(e.description?e.description:e.toString())}})()%22)))';"
onclick="
var co=config.options;
var opt='chkShowRightSidebar';
var show=co[opt]=!co[opt];
var sb=document.getElementById('sidebar');
var da=document.getElementById('displayArea');
if (sb) {
sb.style.display=show?'block':'none';
da.style.marginRight=show?'':'1em';
}
saveOptionCookie(opt);
var labelShow=co.txtToggleRightSideBarLabelShow||'◄';
var labelHide=co.txtToggleRightSideBarLabelHide||'►';
if (this.innerHTML==labelShow||this.innerHTML==labelHide)
this.innerHTML=show?labelHide:labelShow;
this.title=(show?'hide':'show')+' right sidebar';
var sm=document.getElementById('storyMenu');
if (sm) config.refreshers.content(sm);
return false;
">$1</a></html>
!end
%/<<tiddler {{
var src='ToggleRightSidebar';
src+(tiddler&&tiddler.title==src?'##info':'##show');
}} with: {{
var co=config.options;
var labelShow=co.txtToggleRightSideBarLabelShow||'◄';
var labelHide=co.txtToggleRightSideBarLabelHide||'►';
'$1'!='$'+'1'?'$1':(co.chkShowRightSidebar?labelHide:labelShow);
}} {{
var tip=(config.options.chkShowRightSidebar?'hide':'show')+' right sidebar';
'$2'!='$'+'2'?'$2':tip;
}}>>
! How to evaluate a trading behaviour ?
Several approaches can be used to evaluate a trading behaviour. With ATOM, two main approaches are provided:
* an ''ecological'' competition,
* a ''subclasses'' competition.
For both approaches, the principle is to build agents families and to evaluate their performance over several simulations by relying on a their wealth. An {{{AgentFamily}}} is simply a collection of similar agent instances. They are built from an agent instance that represent the initial model from which clones can be created. The wealth used to evaluate how an agent family has scored can rely on several definitions. We use the sum of the agent cash and the valuation of its portfolio (for each asset: number of assets multiplied by the last price for this asset). Because some agents can have a negative wealth, a family can also have a negative wealth. To be able to compute proportional repartitions, we subtract the value of the lowest wealth to have only positive family wealth. Because some behaviours rely on market activity, it is not unusual to add liquidity providers to an evaluation in order to initialize these kind of agents. These liquidity providers are not part of the evaluation so the volume of their population is constant throughout all simulations.
!! Creating your own agent and your own simulation
ATOM allows you to create easily your own trading behaviours and to experiment them in a multi-agent simulation. This tutorial shows you how to proceed to define a trading strategy and to run a simulation with your own agents.
!! Building your own trading agent
All agents in ATOM specialize the Agent class and have to define this method {{{public Order decide(String obName, Day day)}}}. Indeed, this method is called by the simulation engine to query the agent to retrieve its order for a given OrderBook at a given time during the Day.
The following example illustrates the main aspects of the definition of a specific trading behaviour:
* first, subclass the Agent class,
* second, define your own Agent constructor (in this case, we add a {{{period}}} parameter that define when the agent send an order),
* third, override the {{{public Order decide(String obName, Day day)}}} method to define the trading behaviour of your agent (when {{{null}}} is returned, it means that the agent skip his turn).
The source code below illustrates these steps by defining a minimal agent that sends an LimitOrder at a given rate ({{{period}}}).
{{{
import v12.agent.Agent;
class MyAgent extends Agent {
public MyAgent(String name, long cash) {
super(name, cash);
this.period = period;
}
public Order decide(String obName, Day day) {
if (Math.random() < 0.5) {
return new LimitOrder(obName, "" + myId, LimitOrder.ASK, 10, (long) 10000);
}
return null;
}
}
}}}
Several properties are inherited from the Agent class:
* {{{name}}}, the name of this agent,
* {{{cash}}}, the initial cash that this agent has,
* {{{myID}}}, a counter that is used to build unique external identifiers that can be used later to cancel or update a given order,
* {{{numberOfOrdersSent}}}, a counter that represent the number of orders that have been sent by this agent.
It should be noted that these two counters are automatically updated within the {{{public void afterDecide}}} method. If you override it, do not forget to handle them appropriately !
As you can see in this short example, an agent can skip its turn and has not to send an order at each round. This aspect allows to slow agents by skipping some round of talks. Thus, fastest agents are those that always return an order when their {{{decide}}} method is called.
!! Running a simulation with your agents and some ZIT agents
Now that you have defined your agent, you can build a simulation to evaluate it with others agents. To ease the definition of artificial markets simulations, the class Simulation encapsulates market and order books creation and defines a classical extra-day execution. This Day notion is important as it allows agents to reason on time.
A Day in ATOM is made on a sequence of period, a Period being a number of round of talk and a price fixing mechanism (FIXED or CONTINUOUS). By default, you can create a Day that represents a classic EuroNEXT trading day with an opening period (FIXED), the main period (CONTINUOUS) and a closing period (FIXED) thanks to this simple expression {{{Day.createEuroNEXT(10, 1000, 10)}}}.
To build a simulation, the following steps should be respected:
* first, choose the kind of simulation (mono or multi-threaded),
* second, define the price logging mechanism (SHORT or SHORD
{{{
public class MySimulation {
public static void main(String args[]) {
/*
* COMMENT CREER UNE EXPERIENCE AVEC ATOM V11 ?
*
* Tout d'abord, creer une simulation (mono ou multithreadée) Définir la
* manière de logguer les infos (rien, fichier, console) ensuite y
* ajouter carnets d'ordres et agents (autant que l'on veut) et enfin
* lancer l'expérience éventuellement sur plusieurs jours.
*/
Simulation sim = new MonothreadedSimulation();
/*
* Il y a deux types de simulations : MonothreadedSimulation : tours de
* paroles équitables entre les agents Multithreadedimulation : l'OS
* garde le controle sur les agents. Dans une experience classique, sans
* humain dans la boucle, Monothreaded est préférable
*/
//sim.market.logType=MarketPlace.LONG; // ou SHORT
/*
* Deux mécanismes de fixation du prix sont codés dans ATOM : LONG ou
* SHORT. Cela correspond aux nombre de lignes fixées quand un ordre en
* match plusieurs. Avec Long, à chaque ordre touché, une ligne de prix
* est générée Avec short, seule la dernière est affichée. Euronext
* fonctionne en SHORT, mais c'est beaucoup plus clair et facile à
* débugguer en LONG. C'est donc la valeur par défaut.
*/
sim.setLogger(new Logger(System.out));
/*
* Par défaut ATOM ne loggue rien. Si on lui précise un Logger, de
* nombreuses informations sur les ordres, les agents, les prix et le
* rythme de la simulation seront indiqués. En général, l'affichage à la
* console est suffisant et permet le cas échéant, une redirection dans
* un fichier. Sinon : sim.setLogger(new Logger("monfichier.txt"));
*
* Il est aussi possible d'utiliser un FilteredLogger qui permet de ne
* logguer que certaines informations. FilteredLogger flog = new
* FilteredLogger(System.out); flog.orders = true; flog.prices = false;
* flog.agents = false; flog.infos = false; flog.commands = false;
* sim.setLogger(flog);
*
* Sauf cas particulier, il est plutot conseillé de tout logguer avec le
* loggueur classique, puis éventuellement de filtrer le fichier avec
* des grep/awk/sed/cut pour extraire ce que l'on souhaite.
*/
String obName = "lvmh";
sim.addNewOrderBook(obName);
// sim.addNewMicrostructure(new OrderBook(obName)); //idem précédente
/*
* ATOM est multi-orderbooks. Il peut gérer en simultané autant
* d'OrderBooks que necessaire. On associe toujours un titre à un et un
* seul orderbook. Il est aussi possible d'utiliser un OrderBook
* spécifique, par ex utilisant un MarketMaker. Cela se fait alors avec
* addNewMicrostructure(new MarketMaker(name))
*/
sim.addNewAgent(new ZIT("paul")); // cash, bornes par défaut
// sim.addNewAgent(new ZIT("paul",10000)); // bornes par défaut
// sim.addNewAgent(new ZIT("paul",0,10000,20000,10,50));
sim.addNewAgent(new MyAgent("pierre", 0, 1000));
/*
* Il faut ensuite ajouter les agents. ATOM est fourni avec un nombre
* important d'agents. Le plus simple d'entre eux est le Zero
* Intelligent Trader qui envoie des LimitOrder en tirant direction,
* prix et quantité de manière aléatoire entre des bornes éventuellement
* passées en paramètres.
*/
sim.run(Day.createEuroNEXT(0, 1000, 0), 1);
// sim.run(Day.createSinglePeriod(MarketPlace.FIX, 1000));
/*
* On lance ensuite la simulation. D'ue manière classique, une
* simulation dure un certain nombre de jours (si on est en extraday).
* Un jour est constitué comme sur Euronext d'une période d'ouverture
* d'une période continue et d'une periode de cloture. Chacune de ces
* périodes s'exprime en tours de paroles. La ligne ci dessus effectue 1
* seul jour, sans ouverture ni cloture mais avec 1000 tours de parole
* en continu. ATOM permet de construire n'importe quelle structure de
* jour, le premier paramètre de run concerne cette structure, par
* ailleurs accessible aussi à l'agent lors de l'appel à la méthode
* "decide" pour lui permettre de raisonner sur le temps. La méthode
* createEuroNext crée directement une journée en 3 étapes
* fix,continu,fix dont les durées sont respectivement fournies par les
* 3 arguments. Le second paramètre est le nombre de jours.
*/
sim.market.printState();
/*
* Une fois l'expérience terminée il est possible d'accéder à de
* nombreuses informations sur le marché, les agents ou les orderbooks.
* La méthode printState par exemple, indique pour tous les orderbooks
* le nombre d'ordres reçus, le nombre de prix fixés et le nombre
* d'ordres restants sans contrepartie.
*/
sim.market.close();
/*
* Pour fini, il est nécessaire de fermer proprement les espaces,
* notamment si on a utilisé un fichier de log
*/
}
}
}}}
!! Building an agent reasoning on time
This notion of Day is defines a Day that correspond to
class MyAgent extends Agent {
private int declenche;
public MyAgent(String name, long cash, int declenche) {
super(name, cash);
this.declenche = declenche;
}
public Order decide(String obName, Day day) {
if (day.currentPeriod().isContinuous() && day.currentPeriod().currentTick == declenche) {
myId += 10;
numberOfOrdersSent++;
return new LimitOrder(obName, "" + myId, LimitOrder.ASK, 10, 10000);
/*
* C'est à l'agent qu'incombe la responsabilité de gérer les Id de
* ses ordres. s'il ne le fait pas, il ne pourra y faire référence
* dans d'autres ordres comme des Cancel ou des Update
*/
}
return null;
/*
* Bien sur, l'agent a le droit de ne rien faire !
*/
}
public void touchedOrExecutedOrder(Event e, Order o, PriceRecord p)
{
/*
* L'agent est notifié quand l'un de ses ordres a été touché ou exécuté
* A lui de voir ce qu'il fait de cette information.
* Cette méthode n'est pas obligatoire.
*
* if (e == Event.EXECUTED && o.extId.equals(...)
* {
*
* }
*
*/
}
}
package v12.test;
import v12.*;
import v12.agents.*;
public class TutoEN
{
public static void main(String args[])
{
/*
* COMMENT CREER UNE EXPERIENCE AVEC ATOM V11 ?
*
* Tout d'abord, creer une simulation (mono ou multithreadée) Définir la
* manière de logguer les infos (rien, fichier, console) ensuite y
* ajouter carnets d'ordres et agents (autant que l'on veut) et enfin
* lancer l'expérience éventuellement sur plusieurs jours.
*/
Simulation sim = new MonothreadedSimulation();
/*
* Il y a deux types de simulations : MonothreadedSimulation : tours de
* paroles équitables entre les agents Multithreadedimulation : l'OS
* garde le controle sur les agents. Dans une experience classique, sans
* humain dans la boucle, Monothreaded est préférable
*/
//sim.market.logType=MarketPlace.LONG; // ou SHORT
/*
* Deux mécanismes de fixation du prix sont codés dans ATOM : LONG ou
* SHORT. Cela correspond aux nombre de lignes fixées quand un ordre en
* match plusieurs. Avec Long, à chaque ordre touché, une ligne de prix
* est générée Avec short, seule la dernière est affichée. Euronext
* fonctionne en SHORT, mais c'est beaucoup plus clair et facile à
* débugguer en LONG. C'est donc la valeur par défaut.
*/
sim.setLogger(new Logger(System.out));
/*
* Par défaut ATOM ne loggue rien. Si on lui précise un Logger, de
* nombreuses informations sur les ordres, les agents, les prix et le
* rythme de la simulation seront indiqués. En général, l'affichage à la
* console est suffisant et permet le cas échéant, une redirection dans
* un fichier. Sinon : sim.setLogger(new Logger("monfichier.txt"));
*
* Il est aussi possible d'utiliser un FilteredLogger qui permet de ne
* logguer que certaines informations. FilteredLogger flog = new
* FilteredLogger(System.out); flog.orders = true; flog.prices = false;
* flog.agents = false; flog.infos = false; flog.commands = false;
* sim.setLogger(flog);
*
* Sauf cas particulier, il est plutot conseillé de tout logguer avec le
* loggueur classique, puis éventuellement de filtrer le fichier avec
* des grep/awk/sed/cut pour extraire ce que l'on souhaite.
*/
String obName = "lvmh";
sim.addNewOrderBook(obName);
// sim.addNewMicrostructure(new OrderBook(obName)); //idem précédente
/*
* ATOM est multi-orderbooks. Il peut gérer en simultané autant
* d'OrderBooks que necessaire. On associe toujours un titre à un et un
* seul orderbook. Il est aussi possible d'utiliser un OrderBook
* spécifique, par ex utilisant un MarketMaker. Cela se fait alors avec
* addNewMicrostructure(new MarketMaker(name))
*/
sim.addNewAgent(new ZIT("paul")); // cash, bornes par défaut
// sim.addNewAgent(new ZIT("paul",10000)); // bornes par défaut
// sim.addNewAgent(new ZIT("paul",0,10000,20000,10,50));
sim.addNewAgent(new MyAgent("pierre", 0, 1000));
/*
* Il faut ensuite ajouter les agents. ATOM est fourni avec un nombre
* important d'agents. Le plus simple d'entre eux est le Zero
* Intelligent Trader qui envoie des LimitOrder en tirant direction,
* prix et quantité de manière aléatoire entre des bornes éventuellement
* passées en paramètres.
*/
sim.run(Day.createEuroNEXT(0, 1000, 0), 1);
// sim.run(Day.createSinglePeriod(MarketPlace.FIX, 1000));
/*
* On lance ensuite la simulation. D'ue manière classique, une
* simulation dure un certain nombre de jours (si on est en extraday).
* Un jour est constitué comme sur Euronext d'une période d'ouverture
* d'une période continue et d'une periode de cloture. Chacune de ces
* périodes s'exprime en tours de paroles. La ligne ci dessus effectue 1
* seul jour, sans ouverture ni cloture mais avec 1000 tours de parole
* en continu. ATOM permet de construire n'importe quelle structure de
* jour, le premier paramètre de run concerne cette structure, par
* ailleurs accessible aussi à l'agent lors de l'appel à la méthode
* "decide" pour lui permettre de raisonner sur le temps. La méthode
* createEuroNext crée directement une journée en 3 étapes
* fix,continu,fix dont les durées sont respectivement fournies par les
* 3 arguments. Le second paramètre est le nombre de jours.
*/
sim.market.printState();
/*
* Une fois l'expérience terminée il est possible d'accéder à de
* nombreuses informations sur le marché, les agents ou les orderbooks.
* La méthode printState par exemple, indique pour tous les orderbooks
* le nombre d'ordres reçus, le nombre de prix fixés et le nombre
* d'ordres restants sans contrepartie.
*/
sim.market.close();
/*
* Pour fini, il est nécessaire de fermer proprement les espaces,
* notamment si on a utilisé un fichier de log
*/
}
}
/*
* COMMENT CREER UN AGENT ?
*
* Dans sa version la plus basique, un agent hérite de la classe Agent et
* surcharge la méthode decide(obName,day) qui est appelée automatiquement par
* le marché à chaque fois que cet agent a la possibilité de s'exprimer sur cet
* obName. La structure Day permet à l'agent d'avoir des informations sur le
* temps quis'écoule durant l'expérience.
*
* L'agent ci dessous est un agent qui n'enverra qu'un seul ordre à un moment de
* la journée passé en paramètre dans son constructeur. Cet agent, très trivial
* n'a évidemment pour but que de montrer comment écrire son propre agent. Il
* possède néanmoins un paramètre spécifique, raisonne sur le temps et ne parle
* pas tout le temps.
*/
class MyAgent extends Agent
{
private int declenche;
public MyAgent(String name, long cash, int declenche)
{
super(name, cash);
this.declenche = declenche;
}
public Order decide(String obName, Day day)
{
if (day.currentPeriod().isContinuous() && day.currentPeriod().currentTick == declenche)
{
myId += 10;
numberOfOrdersSent++;
return new LimitOrder(obName, "" + myId, LimitOrder.ASK, 10, 10000);
/*
* C'est à l'agent qu'incombe la responsabilité de gérer les Id de
* ses ordres. s'il ne le fait pas, il ne pourra y faire référence
* dans d'autres ordres comme des Cancel ou des Update
*/
}
else
return null;
/*
* Bien sur, l'agent a le droit de ne rien faire !
*/
}
public void touchedOrExecutedOrder(Event e, Order o, PriceRecord p)
{
/*
* L'agent est notifié quand l'un de ses ordres a été touché ou exécuté
* A lui de voir ce qu'il fait de cette information.
* Cette méthode n'est pas obligatoire.
*
* if (e == Event.EXECUTED && o.extId.equals(...)
* {
*
* }
*
*/
}
}
/*
* Il suffit pour utiliser cet agent d'ajouter dans l'expérience précédente la
* ligne sim.addNewAgent(new MonAgent("pierre",0,100); L'agent se déclenchera au
* 100è tour de parole. On vérifiera cela aisément dans la trace d'exécution
* générée.
*/
ATOM can be used in several ways depending on the user's needs :
* sending orders directly to so-called order books,
* sending orders to agents,
* artificial agents with their own trading behaviour,
* executing all the orders from a given file,
* mixing artificial agents with human agents over a network.
In function of your application, you should choose the approach that is most fitted in order to develop has little code as possible :)
!! Sending orders directly to OrderBook
This is the simplest way to use ATOM. In this latter case a simulation simply relies on a minimum set of modules and runs very fast (one day of market activity within roughly less than 5 seconds).
<html> <p><img src=atom_img/case1.png style="width: 12cm; display: block; margin: 0 auto;" alt="atom artificial trading agents market"/> </html>
Short example: [[sending orders manually to an order book|SendingOrdersManually]].
!! Sending orders to agents
Agents do only what you tell them to do and are not endowed with any artificial intelligence : they are simple wrappers. In other words, they are passive entities but however they exist ! Each agent can act in place of a real trader and one can observe the evolution of its holdings.
<html> <p><img src=atom_img/case2.png style="width: 12cm; display: block; margin: 0 auto;" alt="atom artificial trading agents market"/> </html>
Short example: [[sending orders through agents|SendingOrdersThroughAgents]].
!! Artificial agents with their own trading behaviour
One has to design agents’ artificial intelligence. Thousands can evolve simultaneously in real time creating a most heterogeneous population. Once having programmed one of these behaviors, agents evolve by themselves, learning and adapting to the newest economic variables they can access to.
<html> <p><img src=atom_img/case3.png style="width: 12cm; display: block; margin: 0 auto;" alt="atom artificial trading agents market" /> </html>
Short example: [[sending orders through agents|AgentsWithTheirOwnBehaviour]].
!! Executing all the orders from a given file
This is a "replayer" of orders, or to create a file of orders from all the behaviours initially chosen. If you obtain a file of orders from a bank, you can easily compute the price list obtained. You can also for example execute ATOM in a loop : first by creating a set of orders, second by reproducing the execution of these orders.
<html> <p><img src=atom_img/case4.png style="width: 12cm; display: block; margin: 0 auto;" alt="atom artificial trading agents market" /> </html>
The best way to experience this approach is to follow this link: [[Generate and Replay (web)|http://atom.iut-info.univ-lille.fr/simu/]]
!! Mixing artificial agents with human agents over a network
This approach allows to mix human agents over the network, with artificial agents or not, all together using the same market. You can for example use one human agent for each student in a classroom or automated trading agents coming from outside (bank or others) and see what happens. You can decide if human agents stops the market during their reflexion or not. You can set market and agent layout as you want.
<html> <p><img src=atom_img/case5.png style="width: 12cm; display: block; margin: 0 auto;" alt="atom artificial trading agents market" /> </html>
The best way to experience this approach is to follow this link: [[Atom On Web !|http://atom.iut-info.univ-lille.fr/atomOnWeb]]
First at all it's necessary to create a new Java project using Eclipse:
follow menu File → New → Project → Java Project then specify //new project name//.
During this first step, a Java Setting window appears where it is possible to specify required libraries.
Open //tab Libraries// in the form //Java Setting//, then choose //Add External JARs//... and specify the downloaded atom.jar. This is the easyest way to create projects that use the atom.jar library. From then, new Java Class can be developped:
Follow menu File → New →Class.
Don't forget to Import the ATOM package into your new class 'import atom.core.*' and write your own experimentation.
ATOM is a general environment for ''agent-based simulations of stock markets'' developed within the [[Lille University|http://www.univ-lille.fr]]. This simulator is able to closely reproduce the behaviour of most order-driven markets and is more specifically tailored for the [[NYSE Euronext|https://europeanequities.nyx.com]] stock exchange. ATOM is able to efficiently generate, play or replay order flows for intra and extra-days and can be used to design experiments mixing human beings and artificial traders.
As ATOM is developed with the [[Java programming language|http://www.oracle.com/technetwork/java/javase/overview/index.html]], it can be executed on all major operating systems (Windows, OS X, Linux). ATOM can be downloaded from the [[ATOM website|http://atom.univ-lille1.fr/]] or directly below:
<html><center><a Style="background:blue; color:white; font-size:24px; text-decoration:blink;" href=https://github.com/cristal-smac/atom>Click here to download ATOM</a></center></html>
Main authors behind this project are Pr. [[Philippe MATHIEU|https://www.cristal.univ-lille.fr/profil/pmathieu]] ([[CRIStAL|https://www.cristal.univ-lille.fr]]/[[Lille Univ|http://www.univ-lille.fr]]) & Ass. Pr. [[Yann SECQ|https://www.cristal.univ-lille.fr/profil/ysecq]] ([[CRIStAL|https://www.cristal.univ-lille.fr]]/[[Lille Univ|http://www.univ-lille.fr]]) and Pr. [[Olivier BRANDOUY|http://brandouy.free.fr/]] ([[Paris 1 - Panthéon Sorbonne|http://www.univ-paris1.fr/]]).
!!Scientific research
ATOM simulations are organized around three main concepts: ''agent'' (traders or news agents), ''market'' (with orders and order books) and ''simulation'' (the dynamic of one or several trading days). Thus, ATOM can be used at several granularity depending on researcher needs: directly at the order book level, at the market level with several order books are at the ecosystem level with several trading agents passing orders on one or several days.
This modularity enables to experiment trading behaviours at the agent level, market micro structures and their impact at the market/order book level and the global artificial economic ecosystem at the simulation level. For example, you can use ATOM to evaluate new regulation rules or market procedures, experiment the potential effects of taxes or new trading strategies in a sophisticated artificial financial environment which can be of interest, among others, for research in Portfolio Management, Algorithmic Trading or Risk Management.
!!Technological advances for your trading systems
You can either replay past trading days using the real order flow to train your algorithmic trading methods without modifying the existing price series (i.e. "as if" you were in a price-taker, atomistic stock market) or evaluate the impact of your robots in this framework.
!!Educational aspects
ATOM is a smart and very nice tool to learn market finance : it can be used as an experimental software in the classroom or as a simulator for finance newbies.
This short tutorial show how we can create a simple simulation to generate prices thanks to ZIT agents.
To build a simulation, here are the steps that should be followed:
* create a simulation object by choosing a mono or multi-threaded implementation,
* define what kind of logging you need,
* create orderbooks,
* create agents that will be used and add them to the simulation,
* launch the simulation with a specification of the structure of trading day (defaults are provided for ~EuroNEXT) and the number of days to simulate.
Let's apply these steps to build a simple simulation involving 3 ZIT agents, 2 orderbooks and one classical EuroNEXT trading day structure or a continuous trading period.
{{{
/*
* CREATING A SIMPLE INTRA-DAY EXPERIMENT WITH ATOM
*/
import v12.*;
import v12.agents.*;
public class TestIntraday {
public static void main(String args[]) {
// First, you have to choose a mono or multi-threaded simulation (usually mono)
Simulation sim = new MonothreadedSimulation();
/* Second, choose the price fixing scheme: SHORT or LONG
* LONG = each time an order is touched a price is notified (default)
* SHORT = only the last price is notified
*/
//sim.market.logType=MarketPlace.LONG; // or MarketPlace.SHORT
/* By default, nothing is logged. The simulation can be parametrize by
* several loggers:
* - default output stream (terminal): sim.setLogger(new Logger(System.out));
* - a file logger: sim.setLogger(new Logger("monfichier.txt"));
* - a filtered logger (user can choose what is logged):
* FilteredLogger flog = new FilteredLogger(System.out);
* flog.orders = true; flog.prices = false;
* flog.agents = false; flog.infos = false; flog.commands = false;
* It's generally simpler to log everything and use grep/awk/sed/cut
* to select the information you need to post-process.
*/
sim.setLogger(new Logger(System.out));
/* ATOM is a multi-orderbooks simulator and can use a classical double auction
* book (OrderBook class) or a market maker (MarketMaker class).
* As most of the time orderbooks are used, sim.addNewOrderBook(String) is
* mostly used, but sim.addNewMicrostructure accept OrderBook or
* MarketMaker as parameter.
*/
String obName = "LVMH";
sim.addNewOrderBook(obName);
sim.addNewMicrostructure(new OrderBook("AAPL"));
/* Now, we can create ZIT agents to populate our simulation */
// Defaut values: cash=0, minPrice=14k, maxPrice=15k, minQty=10, maxQty=100
sim.addNewAgent(new ZIT("paul"));
sim.addNewAgent(new ZIT("anna",10000)); // cash=10000, default values for other parameters
// cash=0, minPrice=10k, maxPrice=20k, minQty=10, maxQty=50
sim.addNewAgent(new ZIT("bot", 0, 10000, 20000, 10, 50));
/* Everything is now defined so we can launch the simulation.
* the sim.run method needs two parameters: the structure of a day and
* the number of days to simulate. Two static methods are provided to
* handle the most usual day structure: a classical EuroNEXT trading day
* or a simple single period (either FIX or CONTINUOUS for price fixing).
*/
int numberOfDays = 1;
// with this call, we simulate only one day of a classical EuroNEXT trading day,
// with 10 ticks on opening (FIX), 200 in main period (CONTINUOUS) and a
// closing period with 5 ticks.
sim.run(Day.createEuroNEXT(10, 200, 5), numberOfDays);
// Here is another example for a single period of 1000 ticks and a FIX pricing scheme
// sim.run(Day.createSinglePeriod(MarketPlace.FIX, 1000), numberOfDays);
// when the simulation is finished, you can access the market or the agents to
// check their states. The following method allows you to dump some market information
sim.market.printState();
}
}
}}}
readOnly = false;
showBackstage = false;
config.options.chkShowRightSidebar=false;
config.options.chkSinglePageMode= true;