TFG Luis Gonzalez Corujo PDF
TFG Luis Gonzalez Corujo PDF
July 2019
Contents
Table of Contents i
Abstract iii
Resumen v
2 Financial Markets 5
2.1 Looking for the best market to develop a trading algorithm . . . . . . . . . . 5
2.2 Forex Market . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
i
ii CONTENTS
Source Code 89
Bibliography 157
Throughout this project, a complete functional system capable of automating trading actions
in the Forex market such as price analysis and order management has been studied, developed
and implemented.
This core of the system is able to receive a large amount of market prices, analyze them
and determine before each of these new prices the action that has to be carried out: buy
an order or sell an order previously bought. The algorithm can be used either to perform
tests using a database of historical prices, or to trade live connecting to a broker platform.
In much of the development, we have relied on research carried out over several decades of
study, which culminated in a proof-of-concept algorithm called “The Alpha Engine”.
From the beginning, our main objective has been to develop a similar system to “The
Alpha Engine” that could be used in the real world by any user, and to introduce elements
that this model lacks in order to improve its efficiency and operation.
Throughout the chapters of this report, we explain the developments carried out in the
logical module of the algorithm: from a new method to model the Forex market price series
to a system to control the risk that is assumed in each of the open actions, explaining also
the trading strategy and the computation of a statistical indicator of the market liquidity
that manages the aggressiveness with which the algorithm invests, based on the knowledge
of the recent behaviour of the market. In addition, we explain how the architecture of the
system has been designed and defined for the system to be used by any user who has no
more than an Internet connection.
v
Resumen
vii
Chapter 1
1.1 Introduction
Could you imagine a universe in which all tasks and jobs, even the smallest ones, were
performed by robots? Let’s imagine that your smartphone wakes you up in the morning,
you step on the floor that your heating system has warmed up for you a few minutes before
and you go to your smart bathroom that already has prepared you a hot shower (or a fresh
one if it is summer). Meanwhile, your smart kitchen is preparing you your breakfast. Exactly
that breakfast that you like so much. Imagine that your smart car takes you to your job
while you are just paying attention to the news or that selection of music that some device
from the non-so-far future has selected specifically for you. Imagine that all your problems
were solved by a computer or a tablet. Imagine that you could buy anything, even the most
absurd things, through more and more intelligent programs that can suggest you exactly
what you want the most. Even if you didn’t know what that was. Imagine that you had a
device that could get ahead and solve all your needs and problems, even before they appear.
It doesn’t sound bad, does it?
Algorithmic Trading is a method of operating in financial markets that use computer
programs. These programs follow certain rules defined with the objective of executing oper-
ations of purchase or sale of financial instruments. The main benefit of this trading method
is that, theoretically, it can generate profit with such precision and speed impossible to reach
for a human.
Algorithmic trading dates back to the beginning of the 1970s, when it began to com-
puterize the flow of orders in the financial markets. This computerization of market orders
allowed the development of systems such as DOT (also known as SuperDOT), which was
used in the New York Stock Exchange (NYSE) until 2009. DOT was an order routing system
in which orders were sent directly to the screens of specialists, thus avoiding the intervention
of brokers [1]. The specialists were helped by a computerized system called OARS (Opening
Automated Reporting Service) with which they could detect imbalances in the orders be-
fore the market opened, helping them determine the opening price [2]. These two combined
systems allowed to gain in speed and precision, so managing to reduce the number of errors
and thus eliminating human intervention in the order handling process.
1
2 Introduction to Algorithmic Trading
Among technical factors, portfolio insurance, stock index arbitrage, program trading (ob-
viously not mutually exclusive responses), specialist system mechanics, and poor capital-
ization of specialists were the five most frequently cited reasons for the market’s decline
on October 19.
According to this report [4], at that time, several specialists came to suggest limiting
or banning program trading. Most of the support for this measure came from banks and
securities firms, while pension funds were strongly opposed to this possible action. Finally,
the measure was not carried out as they realized that it would be an inappropriate and
unhelpful action.
To this day, the impact of algorithmic and computer-driven trading on market downturns
and crises is not clear and is widely discussed in the academic community.
An important moment for the development of algorithmic trading comes at the end of
the 80s and the beginning of the 90s when arising the fully electronic execution financial
markets.
Another noteworthy fact is the change of decimalization in the United States, which
caused the change in the minimum tick size from 1/16 dollar (US $ 0.0625) to US $ 0.01 per
share in 2001 [5]. This may have encouraged algorithmic operations, since it changed the
micro-structure of the market.
This greater liquidity of the market led institutional traders to divide orders according
to computer algorithms so that they could execute orders at a better average price.
A key point in the history of algorithmic trading was the publication of the paper “Agent-
Human Interactions in the Continuous Double Action” by a team of IBM researchers in
2001 at the International Joint Conference on Artificial Intelligence [6]. In that paper, they
showed, by using an empirical method, how the use of two algorithmic strategies (IBM’s
MGD and Hewlett-Packard’s ZIP) could surpass human traders in the financial markets:
1.1. Introduction 3
Due to the numerous advances in this field, trading algorithms have evolved and increas-
ingly arise more and more in the recent years. Current algorithms are capable of analyzing
several data sources. Among them, it is usual for the most advanced algorithms to analyze,
in addition to the current price of the financial asset, values that provide information on
the state or micro-structure of the market in question, such as opening or closing auctions,
volatility auctions, suspension limits of species and even news published in real time in plat-
forms such as Bloomberg. Some examples of the most used algorithms in recent times are
Chameleon (developed by BNP Paribas), Stealth (developed by the Deutsche Bank), Sniper
and Guerilla (developed by Credit Suisse), arbitrage, statistical arbitrage, trend following,
and mean reversion [3].
In this context, and despite the multiple advances that have been made, a big disadvan-
tage present in all these algorithms is the absence of a completely reliable and consistent
framework that automates the entire trading process and manages to entirely put aside the
human factor. This absence causes the so-called Trading Psychology to come into play in
the current algorithmic trading [7].
Trading psychology refers to the emotions and mental state that can turn out to be a
decisive factor to achieve success or failure in the negotiation of values. Trading psychology
groups several aspects of the character and behavior of an individual that may influence their
commercial actions. These behaviors can vary from greed, which often causes the investor
to stay in a profitable trade for longer than is advisable in an e↵ort to squeeze out the
additional benefits; fear, which causes traders to close positions prematurely or refrain from
taking risks due to concerns about large losses; or repentance, by which to trader may get
into a trade after being missing out on it because of the stock moved too fast.
Trading psychology can be as important as other attributes such as knowledge, experi-
ence and the ability to determine the success of the trade. In algorithmic trading, trading
psychology can influence, for example, the choice and configuration of the indicators, which
is subject to the specific preference of the analyst or trader. In e↵ect, investors mostly apply
ad hoc rules that are not correctly analyzed or integrated into a broader context. Complex
phenomena, such as changing liquidity levels as a function of time, are often neglected.
Fighting against this subjectivity when investing in the stock market has historically
been one of the greatest challenges on the part of investors, as we can see from the following
quote from Edgar Bonham-Carter, CEO of Jupiter Asset Management [8]:
Know yourself. Overcoming human instinct is the key to become an excellent investor.
Fortunately, there is an exception in the trading industry that fully relies on automatic
trading algorithms and minimizes the human factor in the executions. This exception is
4 Introduction to Algorithmic Trading
known as high-frequency trading [9]. The high-frequency trading, also known by its acronym
HFT, is a type of trading that is done using powerful algorithms in an automated way to
obtain market information and depending on this information, buy or sell financial securi-
ties. HFT is a technique that heavily relies on the bases of quantitative analysis. In other
words, HFT uses financial mathematics to carry out market analysis. Generally speaking,
investment positions open by HFT are held for very short periods of time, resulting in quick
purchases or sales of assets. This means that throughout the day thousands, or even tens of
thousands of operations, can be made.
By using mathematical models and algorithms to make decisions, high-frequency trading
has managed to eliminate the human decision factor, causing the replacement of numerous
broker-dealers. For this reason, high-frequency trading is so controversial and has been
subject to numerous criticisms since its inception.
Existing high-frequency trading algorithms make decisions in milliseconds, so a miscon-
figuration can trigger large market movements without apparent cause. An example of this is
the so-called “Flash Crash” of May 6, 2010, when the Dow Jones Industrial Average (DJIA)
su↵ered its largest intra-day point drop ever, declining 1,000 points and dropping 10% in just
20 minutes before rising again [10]. A government investigation blamed a massive order that
triggered a sell-o↵ for the crash. As a result, several European countries came to propose
curtailing or banning high-frequency trading algorithms due to concerns about volatility.
Due to the accuracy and speed required to operate in HFT, algorithms must be extremely
reliable in order to guarantee profit. The accuracy required and complexity of the calculations
that must be done internally are so high that currently no high-frequency trading model can
be considered as perfect and completely reliable.
In this work, we carried out the study, development, implementation and improvement of
an algorithm based on high-frequency trading, which, by using strong mathematical tools,
tries to remove the main disadvantages of the existing algorithms. Specifically, we will
develop an algorithm that will be robust to the market changes and that will need the
minimum possible human intervention. Afterwards, we will show evidence of the execution
and functioning of the algorithm using historical market data.
Chapter 2
Financial Markets
The first step to carry out the development of a high-frequency trading algorithm is to find
the right market for its operation. For this reason, it must be taken into account that the
characteristics of the di↵erent markets can benefit or impair the e↵ectiveness of algorithmic
trading.
In the first place, the market in which high-frequency trading is carried out must be
as volatile as possible. The search for a volatile market, which is often seen as a negative
factor, is due to the fact that algorithms of this type base their functioning on the continuous
execution of mathematical operations which eventually provoke a response to changes in the
market price. The faster and more widely the market price varies, the higher the amount
of operations the algorithm will execute, and in case it is designed correctly, the more profit
will be reaped.
Second, and in relation to the previous paragraph, it is convenient that the market price
is updated as many times as possible during a given period of time. When performing the
mathematical operations with each new price that arrives at the algorithm, the higher the
frequency this value is updated, the more operations will be executed.
Third, it is optimal that the market in which the algorithm works can be accessed at
any time of the day. This is due to the fact that in high-frequency trading algorithms all
negotiation decisions, whether buying, selling with profit or getting rid of an order that
has reached the maximum admitted loss, are taken by the computer. This factor makes it
possible to take advantage of the fact that the algorithm can be working autonomously 24
hours a day without the need for a person to supervise operations.
Fourth, and in order to achieve the maximum profit, the costs of operating in the market
should be minimal, since these trading algorithms are characterized by performing a high
number of operations daily and in short periods of time. The lower the management costs
derived from opening or closing an order, the greater the benefits.
5
6 Financial Markets
Finally, and in order for a high-frequency trading algorithm to work properly, it is neces-
sary for any transaction to be carried out in the shortest possible time, without the market
price changing again in that time.
After taking into account all the above factors and making an analysis of the character-
istics of the main markets in which it is possible to operate using algorithms, we conclude
that, due to its nature, the optimal market for the proper functioning of a high-frequency
trading algorithm is the Foreign Exchange Market, also known as Currency Market, and
commonly abbreviated as Forex or FX.
• Large central banks such as the Deutsche Bank. These central banks are responsible
for providing foreign currency liquidity so that they can be exchanged by the rest of
the agents.
• Other non-central banks such as Citibank or Bank of America. The Forex is the market
where these banks, of all sizes, trade currency with each other.
• Hedge funds and Investment managers like JP Morgan or Morgan Stanley. Investment
managers exchange currencies for large accounts, such as pension funds, foundations
and endowments.
• Large and diverse international Corporations. Firms engaged in importing and export-
ing conduct forex transactions to pay for goods and services.
• Institutional and retail traders. Although the volume of operations of this group is
low compared to financial and emotional institutions, this volume is growing rapidly
in recent years. Retail investors base currency trades on a combination of fundamental
analysis (i.e., interest rate parity, inflation rates, and monetary policy expectations)
and technical factors (i.e., support, resistance, technical indicators, price patterns).
The main purpose of this market is to bring together all international capital transactions
of any kind, whether they come from commercial transactions, financial operations, central
banks or simply speculative movements. In a very simplified way, in the Forex a certain
currency of a country is bought paying with the currency of another. For this reason, Forex
operations always involve two currencies, so traders will always work with pairs of currencies.
To give an example, the most common and used pairs are the euro-dollar pair, the pound-
dollar pair and the dollar-yen pair.
2.2. Forex Market 7
The technical characteristics of the Foreign Exchange Market make it an ideal environ-
ment for high-frequency operations.
First of all, Forex is, by a wide margin, the largest market and with the highest volume
of daily operations in the world, reaching a volume of approximately $ 5.09 billion per day
in April 2016 [12], which is a larger volume than all the other stock markets of the planet
combined.
Second, the market prices of the currency pairs change practically every second. This
rate of change, together with the large daily volume described in the previous paragraph,
make Forex a market with external liquidity.
Another factor that favors this great liquidity is the fact that of the total volume traded
in Forex, approximately 90% is considered speculative, which means that only 10% of the
volume comes from commercial transactions or investments [13]. Therefore, the liquidity
and depth of market that the Forex o↵ers us is incomparable to any other financial market
of the last one.
Unlike other financial markets where the prices of the assets are quoted in reference
to specific values, the Forex exchange rates are symmetrical: the quotes are currencies in
reference to other currencies. The symmetry of one currency against another one neutralizes
the e↵ects of market trends. Due to this property of symmetry, the Foreign Exchange Market
is considered notoriously difficult to predict and negotiate profitably.
Finally, Forex is a market that is not physically centralized anywhere in the world, as it
is in other markets such as the stock exchange, but is part of a large network of negotiation
through international banks with each other. This fact makes it possible to operate on it 24
hours a day, 5 days a week, while closing only on weekends.
For all these reasons, we will focus on the study and analysis of the behavior of the Foreign
Exchange Market, since its extreme liquidity and its symmetry make it the ideal environment
for research and development of fully automated and algorithmic trading strategies.
Chapter 3
In the previous section, we described the anatomy of the Forex market and explained why
it is the best market to focus on for our high-frequency trading algorithm. Among other
things, we mentioned that, unlike the stock market, the Forex opens 24 hours a day five
days of the week. The fact that the Forex has this schedule causes that the activity of the
market may vary enormously throughout the day.
Some events external to the Forex, such as an unexpected action by a central bank or
news such as the results of political elections, may provoke the arise of strong trends in the
market trading activity as a response. A clear example of this, and how chaotic can be for
the health of the market, occurred when in 2011, in the splendour of the Great Crisis [14],
the Swiss National Bank faced the risk of a massive flight of capital invested in the Eurozone
by setting the minimum Exchange rate at CHF / EUR currency pair at 1.20 [15]. This action
provoked very aggressive reactions in the market and during the following year, considerable
losses for the SNB itself [16].
Consequently, it is understood that the financial time series in the Forex Market are
unevenly spaced, which makes the flow of physical time discontinuous. In order to model
these financial time series and to understand the behaviour of the market in a scientific way,
multiple studies have been carried out by di↵erent researchers from 1960s onwards.
Firstly, Mandelbrot and Taylor in 1967 [18] analysed how the price changes over a fixed
number of transactions, establishing that it might follow Gaussian distribution, and also how
the price changes over a fixed time period, establishing that it might follow a Paretian dis-
tribution. Additionally, they introduced a transaction clock that ticks at every worldwide
transaction.
At the end of the 80s, Stock [19] showed that there is evidence that postwar U.S. real
9
10 Developing a High-Frequency Trading Algorithm
Figure 3.1: EUR/USD mid-prices time series defined by physical time and intrinsic time.
The sampling period is over November 5th, 2009. For intrinsic time, the number of events
is 30 determined by a threshold size of 0.1%. [17]
gross national product (GNP) evolves in a time scale other than calendar time. In particular,
in their research, Stock introduced a new time scale defined by the speed of the aggregated
market activity.
In 1995 a key point is reached, when Muller, Dacorogna, Davé, Pictet, Olsen and Ward
in [20] propose the concept of intrinsic time as the cumulative sum of variable market
activity and successfully apply it to the time scale of a Forex forecasting model.
Finally, in 1997, Guillaume, Olsen, Muller, Dacorogna, Pictet and Davé [21] introduce
the directional-change event approach where they use intrinsic time in order to define
time in price series, eliminating any irrelevant details of price evolution between intrinsic
events.
All this research supposed an immense advance in the matter, since they allowed to define
a new concept, the mentioned intrinsic time, that allow us to understand the time di↵erently
as opposed to the traditional concept of physical time. Additionally, in the context of the
markets, this new concept of intrinsic time was used to model the financial price series,
defining a new perspective, the directional-change approach, with which it is intended to
understand the behavior of the market on a more successful way than using physical time.
Using as a basis all this research concerning the use of the concept of intrinsic time to
3.1. The Intrinsic Time 11
model the price curve of the financial markets, Aloud, Tsang, Olsen and Dupuis in [17]
analyse and study the results of applying the directional-change approach to model the Forex
market price series using real data. In detail, they use a data sample with high-frequency
tick-by-tick price data of the currency pairs EUR / USD and EUR / CHF from January 2006
to December 2009. The results presented in this study indicate that the directional-change
event approach may involve improving understanding of the behaviour of financial markets.
Indeed, by correctly applying the concept of intrinsic time, we can model a price curve of
the market in a better way than we would by using the traditional concept of physical time.
Due to the excellent results and, consequently, the large profit opportunity that these
results suggest, we will use the intrinsic time approach as the main basis to model the price
curve of the Forex market in our high-frequency trading algorithm.
In detail, for the algorithm to be developed to be able to perform an adequate analysis
of the market price curve using the concept of intrinsic time, we will distinguish two main
intrinsic events that will occur depending on how that price varies: directional change and
overshoot. However, before explaining these events, we will have to describe several necessary
previous concepts: market mode, short trading, long trading and threshold.
Furthermore, the terms long and short trading are concepts typical of the jargon of stock
markets and trading. Long trading refers to investing in positions that are expected to go
up in price. Long is the usual trading strategy that we understand by investing in the stock
market, according to which, ideally, we will open positions at low values and close them
when this value has risen to produce the expected benefits.
On the other hand, short trading refers to investing with the objective of making profits
when the market falls. In short trading, we will open positions when we believe that the
value of a currency has reached a maximum value from which we think it can only go down,
and we will close it obtaining benefits once the value has dropped.
In order for the short trading to be possible, the investor asks to ”borrow” an amount
of a currency at a certain moment. When the investor wishes to close the position, he must
return the amount of the currency he originally borrowed, making a profit in case the value
of that currency is at that moment lower than when he opened the position.
The last important concept before describing the intrinsic events to take into account is
the threshold. The threshold is a certain percentage value, denoted by , which sets how
much the market price should vary so that we consider that an intrinsic event has occurred.
For example, for a threshold of 1%, if the market price that we take as reference is 5, an
event will be considered when the price reaches either 4.95 or 5.05; see Figure 68
To implement an algorithm capable to detect intrinsic events from a series of prices taken
as input, we will design a function that is able to analyse time series and dissect them into
↵ and ! events for a given %.
Nevertheless, before the design of this function, one last issue must be taken into account.
The development of our algorithm is aimed for a real use, and not only for back-testing. Thus,
in the Forex market, to buy or sell a currency we will find two di↵erent prices at a certain
time: the purchase price, called bid; and the sale price, called ask.
The bid price is the price at which investors are willing to buy the currency., i.e., the bid
price is the best price at which we can sell a currency at a certain time. Conversely, the ask
price is the price at which investors are willing to sell, i.e., it is the best price at which we
can buy a currency at a certain time.
Once these two concepts are properly understood, it is clear that the ask price will always
14 Developing a High-Frequency Trading Algorithm
be greater than the bid price, but usually the di↵erence between these two (called spread)
is not very large, since these values are normally very similar to each other.
Returning to the topic of the algorithm design, we came up with an algorithm designed
in 2017 by Golub, Glattfelder and Olsen called The Alpha Engine [22]. Specifically, The
Alpha Engine is an automated trading algorithm based on the directional-change approach.
The Alpha Engine code is public and can be consulted on GitHub [23].
Due to the similarity between the idea presented in The Alpha Engine and the algorithm
that we want to develop, we are going to use the Alpha Engine’s event detection model as
a base. Thus, the function with which we will detect the directional-changes and overshoots
is shown on next page.
Once the event detection function has been developed, the development of the algorithm
has only just begun. The main question at this point is: once an event is detected, what
does this event imply? This and other of the still unresolved aspects of the algorithm will
be discussed in the next section.
The algorithm must be able to, given a directional change or an overshoot, decide if it is a
good time to open (buy) or close (sell) an order. However, how can the algorithm e↵ectively
predict if after an event the market will follow one or another trend?
Facing this challenge, Glattfelder, Dupuis and Olsen in [24] performed a statistical anal-
ysis research on real time series of the Forex market based on the directional-change event
approach, and as a result of their analysis, they discovered twelve new scaling laws that are
applicable to this type of series.
According [25], in the context of statistics, a scaling law is a functional relationship
between two quantities, where a relative change in one quantity results in a proportional
relative change in the other quantity, independent of the initial size of those quantities: one
quantity varies as a power of another. For instance, one well-known distribution that follows
scaling laws is the Pareto distribution. The probability density function of a Pareto
16 Developing a High-Frequency Trading Algorithm
random variable is
8
> k↵
< ↵ ↵+1 if x > k
f (x) = x
>
:
0 otherwise
where ↵, k > 0 are real parameters, the former called the shape parameter and the latter
scale parameter. Let X be a random variable with Pareto distribution of parameters
↵, k Ifi m, x 2 R. Furthermore, let x1 , x2 , a be real numbers such that a > 0, x1 > x2 ,and
x2 /a > k. Then the following equality holds:
P (X > ax1 | X > ax2 ) = P (X > x1 /a | X > x2 /a)
This formula speaks itself of what a scaling law is. Scaling laws are also referred to as
scale-invariant laws.
Scaling law relationships can be found in multiple natural processes, and they have been
observed in di↵erent areas of knowledge such as physics, biology or computer science. Among
the twelve new scaling laws discovered in [24], it is especially worth mentioning the following:
This scaling law statistically suggests that once a directional change of a certain % has
been detected, it will be followed by an overshoot of the same magnitude of %.
Derived from the discovery of this scaling law, Dupuis and Olsen in [26] introduced
a new trading strategy that, by using the intrinsic events and knowing the properties of
the aforementioned scaling law, can be applied to forecast market trends and decide when
an order should be opened or closed. Dupuis and Olsen called this new trading strategy
coastline trader.
3.2. Trading Strategy 17
According to coastline trading strategy, the pseudocode of the function responsible for
18 Developing a High-Frequency Trading Algorithm
executing operations in our algorithm, depending on the detected events is shown below.
(Algorithm 2).
As stated in equation 3.1, due to the Scaling Law discovered, knowing we are going to
open orders once a directional change has happened, we expect an overshoot of the same
size to occur after. So that, the profit expected for an order will be of the same size of the
directional change that triggered the buy.
The coastline trader model is a countertrend-trading model, which means that a price
drop will cause the algorithm to buy, while a price increase will cause the algorithm to sell.
This type of models provides liquidity to the market, since generally when the price of a
currency moves down means that there is a lack of buyers for this currency, whereas if it
moves up means that there are not enough sellers. This feature of the model is even beneficial
to the markets as a whole.
The student of the University of Essex, Sanhanat Paniangtong, performed in his thesis
[27] an analysis of various strategies derived from coastline trading using real data from
various currencies and various indicators to measure how good and profitable each of the
trading strategies would be. The conclusions of his analysis indicate that coastline trading
can produce great benefits if certain elements were added to improve the strategy such as
Trailing-Stop, aggressiveness control or a liquidity indicator. To be faithful to the truth, on
its own, coastline trading is not a so e↵ective system and can even produce losses in some
situations. We will discuss this in deep detail in the conclusion section of this document.
Therefore, during the next sections, we will study di↵erent features that have been pro-
posed by di↵erent researchers in order to achieve substantial improvement in the coastline
trading strategy.
3.3. The Probability Indicator L 19
Table 3.1: Stats of the orders managed by the algorithm between 2001 and 2019.
As we can see in Table 5.5, from 2008, coinciding with the start of the Great Recession
20 Developing a High-Frequency Trading Algorithm
[14], due to the strong market trend, the algorithm opens many orders that could not be
closed even 11 year later, in 2019, i.e., the algorithm, at a certain moment, can reach to
open many positions that in the long run will not be able to close with benefits. This factor
causes more havoc in a short term than in a long term, because if one could wait indefinitely
until closing the order with benefits, it would not be a problem for the system. The problem
is generated because in the short term, and until the orders are closed with benefits, the
capital used to open these positions is seized, so to speak, and will not be able to be used
to open new orders. In order to solve this issue, Golub, Glattfelder and Olsen [22] added a
new feature to the trading strategy of their Alpha Engine algorithm. This new feature is a
probability indicator of the liquidity of the Forex market, based on the event-based price
curve. This probability indicator is rooted in the extensive mathematical and statistical
theory published in [28] and has the main goal of being able to anticipate and control how
the algorithm will act depending on the di↵erent arriving market trends.
To apply these concepts of information theory to the event-based curve of Forex prices,
following [30], it is understood that the surprise of the event-based price curve will be related
to the probabilities of transitions from the current state, denoted by si , to the next intrinsic
event, denoted by sj , i.e., P(si ! sj ). Since the only intrinsic events that we will take into
account in the algorithm are the directional changes and the overshoots !, we know that
the transition network of states in the event-based representation of the price trajectories
is represented by the following diagram.
Figure 3.8: The transition network of states in the directional-change approach representa-
tion of the price trajectories ! [22]
By looking at Figure 3.8, we know that the possible evolution of states from a directional
change can be either another directional change or an overshoot; and, similarly, the possible
evolution of states from an overshoot can be either another overshoot or a directional change.
Keeping this in mind, in [22], the surprise of transitions from a state si to a state sj is defined
as:
If the transition from state si to sj is very unlikely, the value of i,j calculated using the
previous equation will be very large.
⇢
P(si ! sj ) ⇡ 0, then i,j 0
(3.3)
P(si ! sj ) ⇡ 1, then i,j ⇡0
Consequently, and from Equation 3.1, it can be derived the surprise of a series of prices
in a time interval [0, T] in which K transitions from a state to another one have been
experienced, such as the sum of the surprises of each one of the K transitions. Thus, the
resulting equation, called the surprise equation is:
K
X
[0,T ]
K = log P(sik ! sik+1 ) (3.4)
k=1
This equation can be used now as a measure of the the unlikeliness of a price path. It
is worth mentioning that it is a price trajectory dependent measure. In other words, two
di↵erent price trajectories that exhibit the same volatility may have very di↵erent surprise
22 Developing a High-Frequency Trading Algorithm
values. In case that the value of the surprise of the price trajectory is large, it will indicate
that the price trajectory has experienced an unexpected movement.
Following, again, the article [28], and assuming that we want to be able to calculate the
surprise of a price trajectory of a certain time interval [0, T] using real price data, applying
Equation 3.4 we are going to encounter a major problem: it may happen that in some
periods of time the algorithm may detect very few transitions of intrinsic states, while in
periods of greater activity the algorithm will detect many more transitions of states, which
may a↵ect the fidelity of the value of the resulting surprise. In order to remove the market
activity of surprise calculations, we need to eliminate the component related to the number
of transitions from the surprise within the aforementioned time interval.
Using the Shannon-McMillan-Brieman theorem on convergence of sample entropy [31]
and the corresponding central limit theorem [32], they refer to important quantities, which
will be used in the final expression of the liquidity indicator. The first is H (1) and denotes
the entropy rate associated with the state transitions.
n 1
2X
H (1)
= µi E[ log P(si ! ·)] (3.5)
i=0
where µ is the stationary distribution of the corresponding Markov chain. The authors made
a strong hypothesis in order to simplify the equations and that was assuming that the state
at a given time point only depends on the previous time point. In a previous paper, the
authors claimed that even though they don’t have a formal proof of this fact, the results
they obtained by making this hypothesis were good enough to keep it. That is why we see
the µi values in the equation above.
The next equation to be taken into account is the following.
n 1 2n 1
2X X
H (2)
= µi µj Cov ( log P(si ! ·), log P(sj ! ·)) (3.6)
i=0 j=0
[0,T ]
K K · H (1)
= p (3.7)
K · H (2)
Following the central limit theorem [33], the centered expression of the surprise of a price
trajectory converges to the Normal Distribution when the number of transitions K tends to
infinity:
[0,T ]
K K · H (1)
p ! N (0, 1) for K ! 1 (3.8)
K · H (2)
Thus, we can finally define the liquidity probability indicator with as following equa-
tion:
3.3. The Probability Indicator L 23
!
[0,T ] (1)
K K ·H
L=1 ⇥ p (3.9)
K · H (2)
where ⇥ is the cumulative distribution function of a standard normal distribution.
When the market shows unpredictable behaviour, the probability indicator L will have
an approximate value of 0. Therefore, we can quantify how normal is the market behaviour
and act accordingly: the market shows normal behavior when the value of L is approximate
1.
where S is the set of states built during the discretization process of the price curve. By the
(2)
central limit theorem we know that for large n Hn tends to H (2) . By taking the maximum
value in the right part of this inequality, we obtain the value 2.525729; see [34], [22] for more
technical details.
As for H (1) , there is another upper bound that will allow us to enormously simplify the
calculations. Such upper bound is
(1)
The same reasoning applies for H (1) ; by the central limit theorem, we know that Hn ! H (1)
as n tends to infinity.
To sum up, in order to calculate L value, we will develop a new event detector, setting
the threshold value to 2.525729 · % for the overshoot events (Algorithm 3):
24 Developing a High-Frequency Trading Algorithm
Each time a new event is detected, the value of L will be updated using the equations
H , H (2) , Surprise and L as shown in the following algorithm:
(1)
3.3. The Probability Indicator L 25
Algorithm 4 Algorithm that updates the value of L every time a new liquidity intrinsic
event is detected
1: function Update L(event)
2:
3: if event is not ’No Event’ then
4:
5: if event is ’Directional Change’ then
6: surprise = weight * 0.08338161 + (1 - weight) * surprise
7:
8: else if event is ’Overshoot’ then
9: surprise = weight * 2.52579 + (1 - weight) * surprise
10: p
11: L = 1 - NormalDistributionCumulative ( K * (surprise - H (1) ) / H (2) )
12: return L
Being the variable weight a fixed value used to compute the mean of the surprise over
K transactions and the function NormalDistributionCumulative a method that returns the
cumulative distribution function of the standard normal distribution, previously denoted by
⇥. So that, after getting an event distinct of ’No Event’, the algorithm first computes the
new value of the surprise and then uses this new value to compute the current liquidity L.
By using the probability indicator L, we can control the aggressiveness of the algorithm,
i.e., the capital amount we will use to open an order, whereby, a better risk-adjusted perfor-
mance will be guaranteed.
In detail, following again the AlphaEngine model, when a position is to be opened, the
unit size (volume of capital we will open the order with) will be reduced when the L indicator
starts to approach to 0 of the next shape:
Algorithm 5 Algorithm that updates the value of the unit size depending on the current
value of L
1: function Get Unit Size (L)
2:
3: if L 1 and L > 0.5 then return OriginalUnitSize
4:
5: else if L 0.5 and L > 0.1 then return OriginalUnitSize * 0.5
6:
7: else if L 0.1 then return OriginalUnitSize * 0.1
The implementation of the aforementioned features allows the trading algorithm to work
better in situations that it could not control previously. However, at this point there are
26 Developing a High-Frequency Trading Algorithm
still missing factors that can and should be added to the algorithm so that it works up to
its full potential, which we will explain in future sections.
• The first and most clear conclusion is that, once all the functionalities have been
developed, a great daily benefit can be obtained by using The Alpha Engine algorithm
in Forex market. Regarding this first conclusion, it is a justification to implement all
the functionalities of The Alpha Engine in our algorithm.
• The second conclusion is that the algorithm will not have the same e↵ectiveness for all
the pairs of currencies, and even for some of these it will result in losses. This second
conclusion is going to entail the need to carry out an analysis, through tests with
historical data, of which pairs of currencies will be appropriate to use our algorithm
on and in which pairs of currencies it will be better not to trade. This issue will be
discussed later, once the functionalities are added to our algorithm and we can proceed
to the testing part.
To sum up, by observing Figure 3.9, there is a justification to implement the latest novel
functionality that includes The Alpha Engine. Going into detail, this functionality allows
the trading model to have more freedom, converting what previously were static thresholds
into dynamic thresholds that adapt their value according to the market situation, and its
development will be discussed in the next subsection.
The objective of the development that we will carry out this section is to vary in a suitable
way the value of % used to detect intrinsic events, according to the trend that the market
3.4. Asymmetric thresholds 27
Figure 3.9: Daily Profit & Loss of the Alpha Engine, across 23 currency pairs, for eight
years. [22]
is following at a certain moment. It should be noted that % refers to the threshold value.
When a price that we take as a reference varies by a certain % we will consider that an
intrinsic event has occurred in the market price series. Thus, it is reasonable that the value
% is dynamic and that the algorithm automatically modifies it according to the market
trend. For instance, when the algorithm encounters a very strong up trend, the threshold
with which the overshoot for the market mode is detected should be increasingly becoming
smaller and smaller, with the aim that the stronger the trend, the more intrinsic events can
detect the algorithm, and therefore more operations can be executed.
An important question to answer arises at this point. Knowing that the variations in
the value of the threshold depends on the market trend, does it make sense to take into
account two di↵erent threshold values, up and down , that serve to detect events according
to whether the direction of the movement of the price is respectively up and down?
Golub, Glattfelder, Petrov and Olsen in [35], perform multiple Monte Carlo simulations
of the number of directional changes N detected using asymmetric directional change
thresholds up and down . Specifically, in this study they carry out simulations for the cases
of no trend, positive trend and negative trend of the market. In Figure 3.9 it is shown
the results of these Monte Carlo simulations. By analysing these results, we reach several
28 Developing a High-Frequency Trading Algorithm
Figure 3.10: Monte Carlo simulation of the number of directional changes N as a function
of the asymmetric directional change thresholds up and down . [22]
conclusions:
• For the no market trend situation, we observe that the contour lines are perfect circles.
This shows that the same number of directional changes are found for the correspond-
ing asymmetric thresholds up and down . Therefore, in case of no trend, there is no
di↵erence between using a single threshold or two asymmetric thresholds.
• For the positive market trend situation, we observe that, comparing with the result of
the no market trend simulation, the countour lines shifts to the right. This means that
the threshold up improves the number of directional changes detected using a single
threshold, as long as up is greater than down .
• In contrast to the positive market trend situation, for the negative market trend, we
can observe that, the countour lines shifts to the left. This means that the threshold
down improves the number of directional changes detected using a single threshold, as
long as down is greater than up .
By virtue of the results and conclusions obtained from Monte Carlo simulations, there
is an empirical reason to, from this point, start using two asymmetric thresholds to detect
events depending on the market mode. Thereby, the new thresholds will be defined by:
⇢
up for ↵down and !up
(3.12)
down for ↵up and !down
These new thresholds will henceforth record intrinsic events with di↵erent percentage
variations of the price taken as reference, depending on the direction taken by the movement
of the price.
This change in the thresholds will cause the code of the intrinsic event detection functions
described in Subsections 3.1.3 and 3.3.3 to be changed as well at this point. The new
3.4. Asymmetric thresholds 29
pseudocode of the intrinsic event detection function is shown in the Algorithm 5 shown in
the next page.
The changes respect to the Algorithm 1 defined in Subsection 3.1.3, made with the aim
of introducing the new thresholds up and down , must be also applied in the function of
detection of intrinsic events for the liquidity indicator, i.e. for the Algorithm 3 defined
in Subsection 3.1.3. Recall that the di↵erence between algorithms 1 and 3 is that, in the
case of the detection of intrinsic events for the computation of the liquidity indicator, the
thresholds must be multiplied by the value 2.525729. A more detailed explanation can be
found in Section 3.3.
Once the new asymmetric thresholds have been introduced in the event detection, [22]
proposes a new way to use these thresholds to improve the functioning of the algortithm.
In particular, researchers seek a way of, knowing the trend that is following the market at a
certain moment, screw the thresholds accordingly to compensate.
30 Developing a High-Frequency Trading Algorithm
Getting to vary the value of the thresholds up and down depending the market trend,
allow us to detect more events to close the orders that we have previously opened. In
particular, the operation that should follow this variation in the values of the thresholds is
the following:
8
< When no market trend, then up = down
When market trend is up, then up < down (3.13)
:
When market trend is down, then down > up
However, once again a big problem must be faced in the implementation of this feature:
given a certain price series, how does the algorithm determine if the market follows a non-
trend situation, a positive trend situation or a negative trend situation?
With this aim in mind, [22] propose using the concept of inventory as a proxy or gauge
for the market trend. The inventory of a trader indicates the amount of currencies that, at a
certain moment, the trader owns among all his open orders. For instance, given a coastline
trader that is investing in a certain market such as the EUR / USD, and has opened without
being able to close the following orders: a long order with volume 4, five long orders with
volume 2 and three short orders with volume 1; The value of the inventory of the trader,
denoted by I will be 11, result of the following operation:
I =1·4+5·2 3 · 1 = 11 (3.14)
Algorithm 7 Algorithm that updates the value of I depending on the volume of the opened
orders
1: function Get Inventory (Orders)
2:
3: I =0
4:
5: for order in Orders do
6:
7: if order.agentMode is long then
8: I = I + textitorder.unitSize
9:
10: else if order.agentMode is short then
11: I = I - textitorder.unitSize
12:
13: return I
Conversely, if the inventory of a coastline trader is a very high value, but with negative
sign, it means that the trader has opened many short orders that could not have been closed
at that moment, so the trader should screw the value of thresholds in order to close that
orders. In this case, the short orders will be closed when an overshoot happens while down
market mode is detected. Therefore, it makes sense to reduce the value of the threshold
down when the inventory is a very high negative value, with the objective that the algorithm
detects a large number of down overshoots.
The implementation of the solution proposed with which the value of the thresholds
will be adjusted according to the value of inventory is given by the following equation,
corresponding to a long position:
⇢
down 2 if I 15;
= (3.16)
up 4 if I 30.
And the same equation, but inverted, for a short position:
⇢
up 2 if I 15;
= (3.17)
down 4 if I 30.
From these two previous equations, the variation of the thresholds values will be given
for the next equation:
8
>
> If I 15, then up = 0.75 · up and down = 1.5 · down
<
If I 30, then up = 0.5 · up and down = 2 · down
(3.18)
>
> If I 15, then up = 1.5 · up and down = 0.75 · down
:
If I 30, then up = 2 · up and down = 0.5 · down
The function that allows us to make these fractional changes in the value of the thresholds,
and that will be implemented in our algorithm is described in the Algorithm 8 below.
32 Developing a High-Frequency Trading Algorithm
Algorithm 8 Algorithm that adjusts the value of the asymmetric thresholds depending on
the value of I
1: function Adjust Thresholds(I)
2:
3: if I 150 and I 299 then
4: up = original * 0.75
5: down = original * 1.5
6:
7: else if I 300 then
8: up = original * 0.5
9: down = original * 2
10:
11: else if I 299 and I 150 then
12: up = original * 1.5
13: down = original * 0.75
14:
15: else if I 300 then
16: up = original * 2
17: down = original * 0.5
This function, which updates the values of the thresholds up and down depending of the
value of inventory, must be called each time a trading action occurs, i.e., every time a long
or short order is opened or closed.
In the following figure, we can observe the di↵erent behaviour of the event detection
algorithm after applying this last functionality.
Figure 3.11: Di↵erent behaviour of the intrinsic event detection using fixed (left) and asym-
metric (right) thresholds. [22]
Once the new asymmetric thresholds up and down have been added, the inventory con-
cepts has been introduced and the thresholds value has been screwed according the inventory
value to get a better performance for our algorithm, all the features that Golub, Glattfelder
3.5. The Risk Management Layer 33
y Olsen introduced in The Alpha Engine [22] are fully integrated in our algorithm.
At this point, the algorithm is completely functional and, as discussed in the subsection
3.4.1, o↵ers very positive results. Nevertheless, as the authors of The Alpha Engine them-
selves state in their paper, the algorithm should be understood as a prototype that, after
being tested, shows that directional-change approach will be able to achieve great results
and advances in the high-frequency algorithmic trading in a future, but at the moment is
far from being firmly completed and implemented. In particular, they note that there are
several possible features to add to the algorithm with which from this point the development
could be continued.
Among the possible features to be implemented in the algorithm The Alpha Engine, it
is mentioned that could be added a function that calibrates the various exchange rates by
volatility, or by excluding illiquid ones. It could be also added correlation across currency
pairs in order to increase the performance of the trading model. Finally, it is stated that a
whole layer of risk management could be added for the model.
Our novelty and contribution to The Alpha Engine algorithm will go through, precisely,
developing a risk control system for open orders that allows us to close certain orders when
it is considered preferable to assume a loss before it becomes worse. This functionality will
be the last one that we will add to our algorithm before finishing with its development and
beginning with the testing phase. The details of this latest development will be presented
in the next section.
then the money invested to open an order could remain blocked for an indefinite time. So
that, in certain situations, since every trader makes losing trades sometimes, it is better to
assume the loss and recover part of the investment and use this capital to reinvest in new
shares that, hopefully, will have a better result.
Currently there are multiple risk management techniques used by traders such as One-
Percent Rule, Stop-Loss, Take-Profit, Risk-Reward Ratio or Trailing-Stop. None of these
techniques has been successfully implemented so far in an algorithm that uses the Coastline
Trading strategy, so we will have to study all the possibilities and determine which one is
the optimum to be integrated in our system.
3.5.2 Stop-Loss
Firstly, one of the simplest and most familiar risk management techniques will be explained
bellow: the Stop-Loss. Stop-Loss orders are shares opened in a broker, which upon reaching
a certain price will be closed. The main objective of Stop-Loss is to set a value, usually a
percentage, with which to limit the losses of a trader for a position. In this way, when the
trader opens an order, long or short, a price limit will be automatically set. Once this price
is reached, it will cause the order to close even though a profit has not been obtained [36].
For instance, given a trader in the EUR/USD market opens a long order at a price
of 1.1209 and sets a Stop-Loss of 2%, if the market price reaches 1.0984, the trader will
determine that the loss should be assumed and close the order.
The function that computes the price of Stop-Loss, and that must be called each time
an order is opened is the following:
3.5. The Risk Management Layer 35
Meanwhile the function of a Stop-Loss algorithm for a series of prices would be as follows:
3.5.3 Trailing-Stop
Another simple technique, derived from the basic Stop-Loss, is the Trailing-stop. In gen-
eral, the Trailing-Stop is based on applying the concept of Stop-Loss on the maximum benefit
that an order has achieved. That is, the Trailing-Stop recalculates the Stop-Loss price of an
order each time the market price exceeds the most favorable price recorded since the order
was opened [37].
Given the same example as in the basic Stop-Loss case, if a trader opens a long order in
the EUR/USD market at a Trailing-Stop application price of 1.1209 and sets a Stop-Loss
of 2%, the price of the initial Stop-Loss will be 1.0984. In case the next price that reaches
the Trader is 1.1235, the new Stop-Loss price of the order will be recalculated using this
new price and the same percentage of 2% of previous risk. In this way, the new Stop-Loss
price of the order will be 1.10103. If at that time the market price stops rising and falls to
1.10103, the order will be closed automatically.
The function that updates the Stop-Loss price of an order, that must be called when a
36 Developing a High-Frequency Trading Algorithm
new more favorable price is detected is the same as the one described in the Algorithm 9 of
the previous subsection.
Finally, the function of a Trailing-Stop algorithm for a series of prices is shown on the
next page.
Although Trailing-Stop is a technique that generally has good results, we do not consider
that the Trailing-Stop is the appropriate risk control system. This is due to the philosophy
behind high-frequency trading that is based on buying and selling orders quickly, and not on
holding them for the long-term, so this technique does not represent a great improvement
over the traditional Stop-Loss. On the other hand, implementing this technique involves
performing additional calculations and checks on all open orders for each new market price
that arrives at the algorithm, which means a considerable increase of the response time of
the algorithm.
Due to the added complexity and the little improvement that this strategy implies in
comparison with the traditional Stop-Loss, we determined that this technique is not the
most adequate to implement as risk control.
Once more, the main question is how to determine the risk that should be assumed for
the orders that are opened.
By definition, this technique does not imply a real risk control of the shares, since an open
order would never be closed even if the market was very unfavorable, but rather a strategy
to control trading aggressiveness. In addition, its implementation in our algorithm could
interfere with the position sizing adjustment that is made from the liquidity indicator (more
details in the subsection 3.3.3). Thus, this technique is also not suitable to be implemented
in our algorithm.
The first price, the Stop-Loss, will be the one that will automatically close the action
assuming losses of 5%, while the second price, the Take-Profit, will be the one that will
automatically close the order obtaining the benefit of the expected 10%.
Let ExpectedProfit be the percentage value of the expected benefit of an order, which
takes values from 0 to 1. The pseudocode of a function that computes the Stop-Loss and
Take-Profit prices of an order from the Risk/Reward ratio, and that must be called each
time a new action is opened, is the following:
3.5. The Risk Management Layer 39
Algorithm 12 Algorithm that sets the Stop-Loss and the TakeProfit prices on an order on
a Risk/Reward Ratio strategy
1: function SetRiskReward(Order, RiskRatio, RewardRatio, Expected-
Profit)
2:
3: if order.agentMode is long then
4: order.takeProfit = currentPrice * (1 + expectedProfit)
5: order.stopLoss = currentPrice * (1 - ( RiskRatio / RewardRatio) * expectedProfit)
6:
7: else if order.agentMode is short then
8: order.takeProfit = currentPrice * (1 - expectedProfit)
9: order.stopLoss = currentPrice * (1 + ( RiskRatio / RewardRatio) * expectedProfit)
Meanwhile the function of a Risk Reward Ratio algorithm for a series of prices would be
as follows:
Algorithm 13 Risk/Reward Ratio Algorithm
1: function RiskRewardRatio()
2:
3: for each new marketPrice do :
4:
5: for each order in openedOrders do :
6:
7: if order.agentMode is long then
8: if order.stopLoss > marketPrice or order.takeProfit < marketPrice then
9: sellOrder()
10:
11: else if order.agentMode is short then
12: if order.stopLoss < marketPrice or order.takeProfit > marketPrice then
13: sellOrder()
As we can see in the pseudocode above, for this technique to work, the trader must
decide the value of two variables at the time of opening an order: the Risk/Reward ratio
and the Expected Profit of the order. If we can determine these values by computing them
automatically based on the information we have of the market, and in a way that does not
interfere in the operation of the Coastline Trader, this technique is the most appropriate to
implement in our algorithm.
As stated in their respective definitions, some of the risk control techniques explained
are not suitable to be implemented in a high-frequency trading system following a Coast-
line strategy. Specifically, we rule out the implementation of the risk control system using
Trailing-Stop, Breakeven and Fixed Fractional Money Management techniques. Therefore,
the choice of Risk Management Layer will be between a Traditional Stop-Loss strategy and
a Risk Reward Ratio based strategy.
James B. Glattfelder, one of the authors of The Alpha Engine, in a discussion thread
about the algorithm in GitHub [40] suggests that implementing a too intrusive Stop-Loss
technique might not be a good idea, since it could interfere with the structure of the Coastline
Trading.
As stated in the section 3.2, due to the Scaling Law characterized in equation 3.1, given
an intrinsic event, in order to close an order, the algorithm’s trading strategy will check if
this order has achieved the expected profit. Therefore, every time an order is opened, the
algorithm can compute the Reward price as follows:
setting multiple Stop-Loss values. These simulations have been performed in 7 of the main
Forex pairs of currencies (EUR-CHF, EUR-GBP, EUR-JPY, EUR-USD, GBP-USD, USD-
CAD and USD-JPY) during the period between 01-2014 and 03-2019, giving multiple values
of the original de and multiple values of Stop-Loss. Due to the extend of the resulting
documentation, we have focused on analyzing the results that corresponds to the pairs of
currencies EUR-GBP and EUR-USD, due to the fact that during this period the prices-series
of these pairs showed a very di↵erent behaviour as shown in the figure below.
Figure 3.14: Market prices evolution between Janaury 2014 and March 2019 of the EUR-
GBP and EUR-USD markets.
A summary of the executions of the runs for these currencies for the highest and lowest
threshold values is shown below.
42 Developing a High-Frequency Trading Algorithm
Figure 3.15: Results of the executions on the currency EUR-GBP with threshold 0.025%.
Figure 3.16: Results of the executions on the currency EUR-GBP with threshold 0.075%.
In the graphs, the y-axis represents the cumulative balance of the execution, while in the
x-axis the dates associated with the balance are presented. The cumulative balance of the
execution is computed as the sum of the volume and price of the opened and closed orders.
The higher the value of the balance, the better the results for an execution are considered.
3.5. The Risk Management Layer 43
Figure 3.17: Results of the executions on the currency EUR-USD with threshold 0.025%.
Figure 3.18: Results of the executions on the currency EUR-USD with threshold 0.075%.
From these simulations, we can note that, in the general case, the algorithm starts
obtaining notable benefits from the Stop-Loss value of 10%. So that, our Stop-Loss should
take a value of, at least 5%. However, we can also note that the di↵erence between profits
from a Stop-Loss of 10% to a Stop-Loss of 15% are almost null, but the lower the value, the
more number of orders will be closed.
44 Developing a High-Frequency Trading Algorithm
We can also note that the algorithm is very sensitive to the threshold. For instance, in
the case of the EUR-GBP executions, the algorithm moves from having considerable losses
to obtain profit only by changing the threshold value. This fact may be indicating that
the stop loss value should also be related to the threshold value. Executions show that the
smaller the threshold, worse results are obtained. Consequently, the smaller the threshold,
the smaller should be the Stop-Loss value.
Taking all these factors into account, and knowing that the Stop-Loss must not be too
intrusive in order not to interfere with the Coastline Trading strategy, we propose a method
to automatically compute the Stop-Loss value where, ideally, it takes a value between 5%
and 15%, depending on the value of the indicator L and the threshold that triggered the
event. The lower the indicator L and the threshold are, the more intrusive the Stop-Loss
will be and vice versa, and so, the lower the risk assumed will be. This method follows the
next equation to set the value of the Stop-Loss:
Using this method, we expect have an original threshold value between 0.01% and 1%.
So that, in the best case when the algorithm has a value of L of 1 and a original of 1%:
In the worst case, when the algorithm has a value of L near to 0 and a original of 0.01%:
The pseudocode of the funcion used to set the Stop-Loss and Take-Profit values is shown
below. This function must be called when opening an order:
Additionally, the algorithm that will manages the risk of the opened orders and will
check if, given a new market price, the algorithm must sell an order because the Stop-Loss
or Take-Profit has been triggered has the same shape as the Algorithm 13 (Risk/Reward
Ratio Algorithm).
To summarize, throughout this section we have gone into detail about di↵erent existing
techniques that are used to manage the risk of actions, in order to implement a function that
allows our algorithm to determine when the loss of an order should be assumed. After the
development of this feature, we conclude the development of the High-Frequency Trading
algorithm.
The next and last part of this section is addressed to explain how all the features described
throughout this chapter have to interact and share information between them. So that, we
will try to give the reader an overview about how the algorithm carries out a real execution,
since a new market price is received, until a new order is opened, or an existing one is closed.
Let the variable Event be a string that contains the event that triggered the buy of the
order.
3.6. Putting the pieces of the puzzle together 45
Algorithm 14 Algorithm that sets the Stop-Loss and the Take-Profit prices on an order
using L
1: function SetRiskManagement(Order, Event)
2:
3: if order.agentMode is long then
4: if event is ’downOvershoot’ then
5: order.takeProfit = currentPrice * (1 + down )
6: order.stopLoss = currentPrice * (1 - ( 0.15 - ( 0.1 - (L * down * 10))))
7:
8: else if event is ’directionalChangeToUp’ then
9: order.takeProfit = currentPrice * (1 + up )
10: order.stopLoss = currentPrice * (1 - ( 0.15 - ( 0.1 - (L * up * 10))))
11:
12: else if order.agentMode is short then
13: if event is ’upOvershoot’ then
14: order.takeProfit = currentPrice * (1 - up )
15: order.stopLoss = currentPrice * (1 + ( 0.15 - ( 0.1 - (L * up * 10))))
16:
17: else if event is ’directionalChangeToDown’ then
18: order.takeProfit = currentPrice * (1 - down )
19: order.stopLoss = currentPrice * (1 + ( 0.15 - ( 0.1 - (L * down * 10))))
• An event detector that, having a price series and given a threshold, using the intrinsic
time concept, is able to detect changes in the market mode, update the prices taken as
reference and as extreme, and determine when it occurs an Overshoot ! or a Directional
Change ↵.
• Asymmetric Thresholds, up and down used to set di↵erent threshold values according
to the market mode.
• A trading strategy that, in case an intrinsic event occurs, establishes if it is the right
time to open or close orders.
• A liquidity indicator L, which, based on the recent behaviour of the market, is capable
of determining the amount of money with which an order should be opened at a certain
time.
46 Developing a High-Frequency Trading Algorithm
• A technique to calculate the market trend, using the Inventory concept as the total
volume of the orders the algorithm has opened and not closed yet, and use this infor-
mation to adjust the value of asymmetric thresholds and get orders to be closed easily
before they accumulate.
• A novel system to manage the risk that the algorithm takes when opening an order,
determining the optimal prices to close with benefits, as Take-Profit, and to close
assuming losses, as Stop-Loss.
Having described these elements separately, the last phase of the development is aimed
to bringing all these components together to get them to interact correctly with each other
and perform the joint function of the algorithm correctly.
The details of the necessary requirements, the architecture of the software and the tech-
nologies used for the final development will be presented in the next section, so, for the
time being, we will only try to give the reader an overview of how the interaction between
the elements takes place. To conclude this chapter, the pseudocode below shows the final
behavior of the algorithm in an execution:
• Agent is an object that contains a fixed threshold, an updated value of the unique
liquidity indicator L that corresponds to the agent and a mode that can be short or
long and indicates if the orders sets to be opened are going to be long or short. There
can be multiple agents trading at the same time, using di↵erent threshold values and
both long and short modes.
• The function GetUnitSize(L) corresponds to Algorithm 5 and uses the value of the
unique liquidity of the Agent to adjust the amount of money the order must be opened
with.
• The object newOrder corresponds to the order to be opened and has as a parameter
the amount of money invested and the agent mode that indicates if the order is short
or long.
• The method append(Order) adds the order to the array of opened orders.
The main objective of the previous chapter was to explain and allow the reader to under-
stand each of the elements and the basis of the development behind the operation that will
implement the trading algorithm. Throughout this chapter, we will explain how and once
the bulk of the algorithm is developed, we will design a real system that makes use internally
of the functionality of this algorithm to operate on a real trading platform in real time. This
additionally will allow us to perform tests with historical data of the Forex market.
In order to explain how the system is going to be implemented, firstly, we will define
the requirements that the system must meet. Once the requirements have been defined, we
will use them to design an architecture module so that the system meets the requirements.
Finally, we will choose and explain the technologies considered most appropriate to carry
out the process of implementation.
By the end of this chapter, we will have implemented a real system ready to be tested
by a user who wants to check how the algorithm performs on historical data or on the real
time market.
• The algorithm must be able to obtain bid and ask prices for every new market price.
49
50 Implementing the system
• The algorithm must store the value of the threshold, mode and liquidity of all
of its agents.
• Given a price and a threshold, the algorithm must be able to detect if an intrinsic
event has occurred.
• In case of an intrinsic event, the algorithm should be able to determine whether any
orders should be opened or closed.
• The algorithm must be able to detect intrinsic events of the liquidity given a price
and a threshold.
• In case of an intrinsic liquidity event, the algorithm should update the agent’s liq-
uidity.
• When opening an order, the algorithm must be able to determine the amount of money
with which it will open depending on the value of the liquidity L.
• The algorithm must be able to determine the value of Stop-Loss of an order based
on the market price and the liquidity L.
• The algorithm must be able to determine the value of Take-Profit when opening of
an order based on the market price and the threshold.
• The algorithm must be capable of updating the value of the inventory after opening
or closing an order.
• The algorithm must be able to update the values of the asymmetric thresholds
when the inventory is updated.
• The system must be able to obtain prices in real time from a broker.
• The system must be able to perform algorithm executions with prices in real time.
• The system must be able to perform algorithm executions with historical prices.
• The system must be able to perform algorithm executions using historical prices of the
Forex market.
• The system must have an interface that allows the user to customize the executions.
• The user must be able to enter the credentials of his personal broker account.
• The user must be able to choose the currency with which he wants to operate in real
time.
• The user must be able to choose the currency with which he wants to perform historical
executions.
• The user must be able to choose the threshold with which he wants to perform historical
executions.
• The user should be able to consult the results of the balance once the historical exe-
cutions have finished.
• The user must be able to consult the statistics of opened and closed after the historical
executions.
• The database should store historical prices of the currencies with which they want
perform to historical execution.
• The database must store the orders that are opened along with the current data From
the market.
52 Implementing the system
• The database must store the orders that are closing along with the current data From
the market.
• The database must be able to calculate, based on open or closed orders, the total
balance after an execution.
• The database must be able to calculate, based on open or closed orders, the statistics
after an execution.
From this view, we define the objects needed to program the algorithm which will im-
plement all the logical modules of the program.
• Presentation Layer: Layer that includes the components in which the interaction
between user and system takes place.
• Logical Layer: Layer that includes all the controllers responsible for carrying out the
4.2. Software Architecture Design 55
price and order analysis and other main actions of the algorithm. As its name suggests,
this layer contains all the logic of the program.
• Physical Layer: Layer that includes all the components responsible for establishing
connection between the modules.
soon, be patient.
We can see the screens sequence of a historical execution and a live execution on the next
few pages:
4.3. Development of the user interface 59
Figure 4.9: Designs of the tables and the relationships between them that the Datamodel
must contain.
The function of each of the tables shown in the design of the data model is briefly
described below:
• Historical Prices: this table must contain information about bid and ask historical
prices of the market, and the date and time the price was registered. With the aim
of having appropriate data for the operation of a high-frequency algorithm, the data
frequency of the prices to be stored must be one price per minute and the period will
be between January 2001 and March 2019.
• Opened Orders: this table must contain all possible information about the orders set
to be opened: open price, date and time, volume, liquidity, Stop-Loss price, Take-
Profit price, long or short mode, event that triggered the buy, etc. This table will refer
to Historical Prices table using the open price. Once the order is closed, it must be
removed from this table.
62 Implementing the system
• Closed Orders: as in the Opened Orders case, this table must contain all the informa-
tion of the order when this order is set to be closed, adding some information such as if
the order was closed by Stop-Loss or Take-Profit. This table will also refer to Historical
Prices table using the close price. Additionally, this table will refer the Opened Orders
table storing its Original Id.
• Liquid value: this table will be update when the algorithm opens or closes an order,
and will update the current liquid value of the execution up to that time.
• Monthly Stats: this table will also be updated once the algorithm finish analyzing all
the historical prices of a month, and will store in tables some execution statistics as the
number of opened and closed orders, the percentage or closed orders, the percentage
of Stop-Loss or the percentage Take-Profit orders that has taken place in a certain
month. After the whole execution, the table will be updated, adding a row with the
total statistics results.
These tables and relationships must be created for each pair of currencies that the system
must work with. In other words, the Data Model will have unique tables of historical prices,
opened orders, closed orders, order movements and execution statistics for each pair of
currencies with which we want to perform simulations of the algorithm.
The data flow between the algorithm and the database follows the diagram below when
the algorithm performs an action (buy or sell) is shown below.
4.5. The Technologies of the Implementation 63
With the aim of creating a Database that is not too big and difficult to migrate, we have
chosen only seven of the main Forex currencies to store data. These seven currencies are
EUR-CHF, EUR-GBP, EUR-JPY, EUR-USD, GBP-USD, USD-CAD and USD-JPY.
It must be noted that, if a user wants to perform simulation on another pair of currencies,
he can provides his own data feed.
• The Math library: provides access to the mathematical functions defined by the C
standard. This library is mainly used to compute values such as the Liquidity Indicator
L
• The Pandas library: provides high-performance easy-to-use data structures and data
analysis tools. This library is used to process the results and statistics of the executions.
• The Matplotlib library: is a plotting library which produces publication quality figures
in a variety of hardcopy formats and interactive environments. This library is used to
plot the results of the executions.
• The PyMySQL library: provides the needed driver to connect Python code to a
database. This library is used to perform the connection to the historical prices
database.
• The Tk library: provides a robust and platform independent windowing toolkit that
can be used to design graphical interfaces that interacts with the python program.
This library is used to develop the user interface which the user can perform actions
in the system with.
• The pyTest and Coverage libraries: provide a framework that makes it easy to write
small code tests. These libraries are used to perform the unitary tests of the logic of
the algorithm.
• The FXCMpy library: provides a RESTful API to interact with the FXCM trading
platform [43]. Among others, it allows the retrieval of real time streaming market
prices data. This library is used to establish the connection between the algorithm
and the real time trading broker platform.
The final class diagram of the objects used by the implemented algorithm is shown below:
4.5. The Technologies of the Implementation 65
Figure 4.11: Class Diagram of the objects, attributes and methods of the Implemented
Algorithm.
In Section 4.4 we defined and designed the Data Model. In order to implement this Data
Model meeting the Database Requirements and adequately performing the Data Flow, it
has been created a relational database using SQL technology. We have opted for a relational
database instead of a non-relational database for several reasons:
• We have extensive prior knowledge in SQL technology that allows us to develop the
required actions in an easier way.
• Currently, most commercial servers o↵er the migration of SQL databases, but just
very few o↵er to store non-relational databases. In addition, the servers that o↵er this
service represent a significant increase in the monthly price.
66 Implementing the system
• The connection from the algorithm to the database can be carried out in a very simple
way from the code when the database is SQL, since the existing libraries have extensive
documentation.
• Ease of configuration so that the data can be consulted, inserted and modified by the
users of the program without the need to assign special permissions.
• Possibility of guaranteeing the data validity even in the event of errors, power fail-
ures in the database due to ACID properties (Atomicity, Consistency, Isolation, and
Durability) [44].
To sum up, a relational database complies with all the necessary requirements, is inex-
pensive and provides a good performance in the data processing during the executions.
As previously stated, to correctly integrate the database in the algorithm operation, it
has been used the PyMySQL library. This library allows to connect the database from the
system execution environment and execute SQL sentences from the code. We can select
the data, perform insertions of orders and statistics, update the rows stored and delete the
opened orders when they are set to be closed using algorithm objects. For instance, we can
insert into the ’Opened Orders’ Database table an order declared in the algorithm, which
contains internal data such as the current liquidity indicator or inventory values.
In order to the Historical Prices Database to be consulted by any user through an in-
ternet connection, the database will be uploaded to an online server. The connection is
automatically made from the Python code when historical tests are executed.
The implemented data model for one currency pair, after determining which fields should
be stored in each of the tables is shown below. Recall that it must be replicated for all the
pairs of currencies we want to store.
Finally, to support the main functionality of the algorithm, apart from running tests
with historical data, it is necessary that the program establishes a connection with a trading
platform that allows it to obtain market prices in real time and opening and closing orders
simulating the behaviour of a real trader. As established in the architecture of the system,
this connection must be made through the HTTPS protocol. In other words, an external
service to our system must provide us with market data through an API connection that
uses the Internet. The trading platform chosen to make this connection is FXCM.
FXCM, also known as Forex Capital Markets, is a retail trading broker in the foreign
exchange market, based in London. Accessing to the FXCM database which stores data
from multiple currency prices is public and free. In addition, this broker provides all the
necessary services to be used by our algorithm. The fact that the broker manages orders
internally in its server and that the algorithm can consult them by only making calls to the
API, means that our program does not need to store the opened and closed orders or the
statistics and balance data, what supposes a big reduction in the operational complexity.
That is, the algorithm will only have to handle of receiving the last market price, analyze it
and inform the broker if an order should be opened or closed.
In addition of providing these services, FXCM also provides a user interface on its website.
This interface allows the user to consult the orders that have been opened, closed and other
4.5. The Technologies of the Implementation 67
interesting data such as the balance of the account or the recent evolution of the markets.
Therefore, a user who wants to use the algorithm as a real trading system, will only
have to open an FXCM account and enter his Token API. As the action of creating a Demo
account is allowed without the need to enter real money, the user will be able to test the
algorithm in real time without incurring any kind of expense. However, if a user also wishes
to operate with real money he can.
Operating in real time, it has been observed throughout various executions that the
algorithm is very sensitive to the chosen threshold value. In order to the user not to choose
an atypical or not optimal threshold value, the algorithm will always use the same number
of agents and the same favorable thresholds. Therefore, when the algorithm is executed in
real time, the following agents will be trading:
To sum up, so far, we have implemented a Python program that is able to run a high-
frequency trading algorithm either using historical market prices, by connecting to a SQL
database, or trading in real time market with a Demo or real account, by connecting to
FXCM broker platform.
Having done that, our system meets all the defined requirements and is ready to be used
in the real world. However, before putting an end to the project too early, in the next
chapter we will try to ensure, by performing multiple tests, that both the development and
the implementation have been carried out correctly and that the final product is ready to
be used.
Chapter 5
After the Development and Implementation of the System phases, the last part with which
we will conclude the Project is the Verification of the system behaviour. The Verification
phase is carried out by conducting tests. These tests are performed, not only to validate the
correct operation of the system, but also to check the efficiency of the algorithm compared
to The Alpha Engine. For that purpose, we have split this section into five parts, each of
them clearly di↵erentiated from the others and with its own objective:
• First, it will be performed unit testing for the components of the main algorithm. I.e.,
we will program unitary tests using tools of automation to ensure the elements of the
algorithm are working correctly and as expected.
• Secondly, tests will be carried out to verify that the data is being stored correctly in the
Database. In this part we will ensure that the data is being communicated correctly
between the algorithm and the Database.
• Thirdly, user tests will be carried out to verify that the user interface is working as
it should and that the data the user gives is being communicated correctly to the
algorithm.
• Fourth, efficiency tests will be carried out among the di↵erent versions of the algorithm.
These tests are made in order to compare which of the development versions strategies
obtain a higher return.
• Finally, we will perform real executions to verify that the algorithm works correctly
with the trading platform. That is to say, the algorithm obtains real time price data
and uses it to detect intrinsic events and buy or sell shares automatically.
69
70 Testing and Verification
A unit test is a method to check the correct operation of a code unit. For example,
in object-oriented programming, the unit test must check the operation of the methods of
a class separately. The unitary testing serves to ensure that each unit functions properly
and efficiently. In addition to verifying that the code does what it is supposed to do, with
unit tests it is also verified that the method name, the attributes, variables and types of the
parameters and the returns are right.
Due to this reason, this first testing section shows how the automated unit tests are going
to be performed for each of the algorithm elements developed in Chapter 3.
Therefore, the components that must be tested are the logical classes and methods of the
algorithm. These classes and methods were described in the previous chapter in the class
diagram (Figure 4.11).
The unit test will be coded in Python language using the library Unittest and the tool
Coverage.py to graphically obtain a report of the lines of code that have been covered by
the unit tests.
As the reader can see, all the elements and methods of the file classes.py, which contains
the objects Agent, EventsRecord, LiquidityIndicator, Price and Order, have been tested
successfully. So, the 100% of the code lines are covered and correctly tested.
order is closed, and If the statistics and the balance of the execution are correctly computed
automatically once the algorithm ends the execution.
To perform this first Data Model test we have programmed the next Python code that,
after executing, should store a row in the EUR-USD Opened Orders Table with the following
fields:
• Volume: 87
• Take Profit:2.8
• Liquidity: 0.4
• Inventory: 450
After executing the code, we will verify if the order was successfully inserted in the
database.
The result of the first test is shown in the figure below.
72 Testing and Verification
Figure 5.3: First test code and evidences that the row was properly inserted.
Afterwards, we close the order previously opened and we verify in the Database that
the order was removed form the Opened Orders table and that it was stored in the Closed
Orders table.
Figure 5.4: Second test code and evidences that the row was properly inserted as a closed
order.
Lastly, we will perform an execution to verify that statistics data is consistent with the
stored orders. The execution uses historical prices of the pair of currencies EUR/CHF from
Janaury 2019 and Febraury 2019 with Original Threshold and Stop Loss value of 0.01%.
The stats generated in a .csv file are shown below:
Table 5.1: Stats of the orders managed by the algorithm in the last test.
Now we assert that the statistics match the data stored during the execution:
Figure 5.6: Checking that the algorithm open orders and they appear in the broker platform’s
interface.
ments were added to the aim of improving the benefits a user can obtain from the algorithm.
Due to this reason, during this part we will perform efficiency tests on the returns of each
of the versions of the algorithm.
The versions to be tested are the listed below:
• Version 1: version that implements the basic elements of the algorithm: detection of
intrinsic events and Coastline Trading strategy.
• Version 2: version that contains the elements of the Version 1, added the Liquidity
Indicator L used to control the aggressiveness with which orders are opened.
• Version 3: version that contains the elements of the Version 2, added asymmetric
thresholds and the Inventory concept used to control the market trends. The features
of this version matches with The Alpha Engine features
• Version 4: final version that contains the elements of the Version 3, added a risk
management layer that sets Stop-Loss and Take-Profit prices every time an order is
opened.
To perform these tests, we will compare the results of the balance and statistics of opened
and closed orders in executions for each of the versions using the same data set, the same
thresholds and the same number and mode of agents.
To analyze the results, two indicators will be used:
• Cumulative Liquid value: the cumulative liquid value is the total worth of the whole
execution up to a certain time. It is computed by adding the total profit or loss of all
the previously closed orders and the current situation on the opened orders not closed
yet. This indicator is the most accurate to perform these efficiency tests, since it does
not take into account only the closed orders, but also the opened at a certain point. So
that, if the algorithm cannot to close a large number of orders that accumulate losses
it will be penalized.
• Closed Rate: using the execution statistics, it will be analyzed the number of orders
that, among all the opened, were succesfully closed.
Below, it is shown pseudocode of the function used to get the Cumulative Liquid Value
in a certain point of the execution.
76 Testing and Verification
The environment chosen to perform this efficiency tests corresponds to the same published
in the Alpha Engine code [23], so we can carry out a suitable comparison between their
algorithm and ours and find out if we really have improved the efficiency.
It has been used:
• Four long agents and four short agents with the original threshold values 0.25%, 0.5%,
1% and 1.5%.
The results of the efficiency test performed on the di↵erents algorithm versions are shown
in the next subsections.
5.4. Efficiency Testing 77
Figure 5.7: Graphic of the results of the Cumulative Liquid Values of the execution of the
Version 1 in all of the aforementioned pairs of currencies
Table 5.2: Table of the Closed Rate for all the currencies in the Version 1
78 Testing and Verification
Figure 5.8: Graphic of the results of the Cumulative Liquid Values of the execution of the
Version 2 in all of the aforementioned pairs of currencies
Table 5.3: Table of the Closed Rate for all the currencies in the Version 2
5.4. Efficiency Testing 79
Figure 5.9: Graphic of the results of the Cumulative Liquid Values of the execution of the
Version 3 in all of the aforementioned pairs of currencies
Table 5.4: Table of the Closed Rate for all the currencies in the Version 3
80 Testing and Verification
Figure 5.10: Graphic of the results of the Cumulative Liquid Values of the execution of the
Version 4 in all of the aforementioned pairs of currencies
5.4. Efficiency Testing 81
Table 5.5: Table of the Closed Rate for all the currencies in the Version 4
• In Version 4, during this risky end of 2011 period, there is a loss up to -250 units.
Although in versions 1, 2 and 3 after 2011 the Cumulative Liquid Value is stabilized,
if the execution had been completed by the end of 2011, Version 4 would be the only one
that could face the losses derived from the currency pair XAG/USD. As a real user of a
trading system does not have umlimited money and time to invest and wait for the market
to stabilize, we consider this point a huge factor in favor of the Version 4.
On the other hand, regarding the Close Rate, although the di↵erence between versions
may seem tiny, a 1% of the large number of orders managed by the algorithm throughout the
execution can make a huge di↵erence, since, generally, a losing order supposes way more risk
than the reward that a winning order does. That is, it is very important that the algorithm
manages to close as many of the orders as possible with profit, but in case profit cannot be
achieved, the orders must be closed quickly before the losses accumulate.
The results of the Close Rate indicator obtained suggest that, although the percentage
of profit closed order may be lower than the rest of the versions due to the Stop-Loss factor,
again Version 4 seems the most appropriate to use in a real trading system, because it reduces
the risk derived from large losses.
Once again, we address the reader to the appendix if he wants to consult the complete
results in detail and judge the results by themselves.
To sum up and as a conclusion, the Version 4, which introduces a risk management layer
to the algorithm, provides a gain in security to an investor who is investing real money and
does not have unlimited time and money. As a proof of concept, Version 2 and Version 3 of
the algorithm can meet and even obtain profits by removing the illiquid pairs which obtains
no benefits, but if we had to choose a version to implement in a real system, we consider
that, due to the risk control system introduced, Version 4 is the most appropriate.
Chapter 6
The environmental or anthropic impact is the e↵ect produced by human activity on the
environment. In this context, the impact of the project is the possible environmental impact
that, for better or for worse, the development, implementation, testing and execution may
cause. As long as the result of this Final Degree Project is a piece of software product, which
does not require any manufacturing process or external component, beyond a computer to
be run, we consider that the environmental impact of the project is negligible. However,
it is worth mentioning that in order to put into operation the developed product, it will
be required a functioning computer and an 24 hours on-line server containing the historical
database so that the user is able to run tests historical when he wishes.
If the user chooses to connect the algorithm to the trading real time broker platform, the
program must be kept running during all the entire execution time, so, consequently, the
system needs to have a permanent source of energy, with a subsequent energy expenditure.
This point, derived from the chosen Client-Server architectural pattern, might be solved in
the future, by changing the architecture to a Cloud-based one. This change would improve
both performance and the energy saving.
On the other hand, the social impact is the e↵ect the product have on the well-being of
the community. In this context, we consider that the social impact of the algorithm is greater
than the environmental impact, due to the sensitive subject the trading world is. On one
side, the positive social impact is that, due to its nature, the algorithm provides liquidity to
the market. Since its emerge, the trading algorithm have been criticized and limited because
its appearance used to a↵ect negatively to the market micro-structure. The trading strategy
used in our algorithm, the Coastline Trading, is a counter-trending strategy: the orders are
opened when the rest of the market actors are selling, and these opened orders are sold when
the rest of the market actors are buying.
Another social impact of the software product that can be taken into account is the fact
that it allows to automate tasks that traditionally have been carried out by humans such as
83
84 Environmental and Social impacts and Ethical and Professional Responsibilities
analysing the market behaviour and the recent trends or managing the orders. Although this
algorithm may not be yet a reliable version that allows to fully remove the human factor, it
can be taken as a basis for future research to gradually erase the role of the human of the
trading world.
Most of the Ethics and Professional responsibilities of the project is related to the process
of obtaining, processing and storing the data used. Firstly, it is critical to ensure that the
user personal account data is not stored, processed or used for the own behalf by the system
developers. This personal data may contain sensitive economic data such as the monthly
income. Additionally, the historical market data used to test and document the algorithm
must be true, exact, complete and verifiable, so this data must not be rigged in order to
show the most convenient results. The used historical prices data are public and have been
obtained free of charge.
Regarding ethical responsibility, the authors of the Final Degree Project in no case intend
to cause harm or loss to the user. However, in case the user wishes to invest real money, he
must bear in mind that the algorithm does not guarantee at any point a winning formula to
return income. It must be remembered that the algorithm is a proof of concept and, although
certain simulations show profits, to perform these simulations the algorithm is supposed to
have an unlimited amount of money to invest. If the user wants to perform a real investment,
the amounts used to open orders should be adjusted according to the available money. For
this reason, we do not recommend a user to invest a large amount.
Chapter 7
To conclude this project, in this last chapter we will take a look back and review all of the
work that was done. This section will expose the general and personal conclusions that we
have drawn from the study and subsequent development and implementation of the project.
Finally, We will discuss multiple lines that may serve as a basis for future research and
improvements to the work presented here.
85
86 Conclusions, Model Criticism and Future Work
algorithm uses, and we would like to take this point to present our critical vision of the line
of research referred to throughout the Development chapter.
First, it seems inappropriate to build a trading algorithm without taking into account
money or time. In this context we must note that, like the authors of The Alpha Engine, the
models up to this moment are a proof of concept with the aim of noting that the investigations
of the directional-change event approach to model trading systems can provide results if the
investigation continues. But, from now on, we believe that future researchers should take
into account that the trader must have a maximum budget with which to invest in the
market.
Another weak aspect that we have found is that the documentation referring to the
liquidity indicator is not entirely clear. The liquidity indicator was by far the hardest module
of the entire system to develop, understand and explain. To develop it, we used several
documents that are referred to in this document’s bibliography.
However, these documents do not clearly indicate the methodology and development of
this module. The code published in GitHub by the authors of The Alpha Engine is neither
well documented nor self-explanatory. There are multiple variables and methods whose
names are not descriptive, and there are variables that have values chosen arbitrarily without
any justification. We think that the published code could have been better documented,
better structured, could have had more descriptive names and followed better code patterns
and recommendations.
Finally, we would like to mention that, in our opinion, our version of the algorithm can
improve the performance in a real execution with respect to previously developed algorithms
based in directional-change events, which was one of our main objectives at the beginning of
the of this project. The aspects that we think we managed to improve with respect to The
Alpha Engine are the following:
• The fact of providing an architecture to the system that allows a user to easily interact
with the algorithm and see for themselves the results of the executions.
• Up to this point, the Alpha Engine only allowed testing the model but did not provide
a data feed, which forced the user to obtain its own data feed. Our system allows
the user to use the algorithm in the real world when connected to a trading platform.
In addition, the user will not need to provide their own data feed, the algorithm can
connect to our historical database which will pass the data directly to the algorithm.
• As the performance tests have showed us, thanks to the risk management system
developed, our algorithm can independently manage money from an investor in a much
safer way compared.
• Therefore, a user who trades with limited time and money, will obtain obtain acceptable
results in the medium and long term due to the increased performance of our algorithm.
7.2. Personal and educational conclusions 87
• Documentation and study based on existing research. This is the case of the de-
velopments of the algorithm modules that had been previously developed and whose
development is detailed in the documents taken as reference throughout the project.
This is the case of the detection of intrinsic events, the Coastline Trading strategy, the
liquidity indicator and the asymmetric thresholds for the detection of events.
• Own investigation, trial and error. Specifically, in the case of finding the best risk
control method, we had to investigate and choose between the di↵erent strategies used
in the real trading world. Once the strategy was chosen, we had to identify the optimal
values with which to assign the output values of the opened orders. We executed several
simulations for multiple values and we discovered that the algorithm is very sensitive
to the market and the threshold value, this helped us to later determine a function that
assigns risk to an order depending on the market liquidity and the threshold value.
• Application of knowledge acquired during our software degree. For the implementation
and testing phases of the system, we applied knowledge obtained in various courses
throughout the degree. For instance, defining the requirements and architecture or
unit tests of the system are part of the software construction process that we have
learned.
On the other hand, in the personal field, we feel that we have grown in aspects that every
engineer must have. We have increased our resilience and improved our self-learning ability.
The realization of this project has allowed us to obtain skills that when we started, we
did not think we were going to learn in this process. The fact that we had to soak up a
multitude of scientific documents, in large part with advanced statistical and mathematical
concepts, has encouraged us to know that in the future we will be able to face projects with
concepts that we ignore and that can be intimidating at the beginning.
In addition, most of the technologies used in the final system were unknown to us before
starting the project. We would also like to name many other aspects that, although we
have not gone into much depth, are present in the project. Big Data in the mining, storage
and processing of data, the creation of a client-server architecture system, development of a
graphical user interface, unit tests, the automation of efficiency tests and the analysis of the
data produced by the system.
Regarding aspects not related with technology, we highlight the theoretical knowledge
acquired about macroeconomics and about the structure of the stock and currency markets.
We now have a starting point in a topic of our interest, as it is algorithmic trading, to
continue studying and developing better future projects.
In summary, this project has helped us to grow enormously. For us it has been an
experience that we could have hardly ever experienced doing another type of project.
88 Conclusions, Model Criticism and Future Work
import t k i n t e r a s tk
from t k i n t e r import t t k
import c l a s s e s B r o k e r a s a lp h a
import time
import m a t p l o t l i b
from m a t p l o t l i b . backends . b a c k e n d t k a g g import FigureCanvasTkAgg
from m a t p l o t l i b . f i g u r e import F i g u r e
import m a t p l o t l i b . p y p l o t a s p l t
import fxcmpy
import m a t p l o t l i b . d a t e s a s mdates
import DBConnection a s dbc
from h i s t o r i c C l a s s e s import Agent
from h i s t o r i c C l a s s e s import P r i c e
import t h r e a d i n g
m a t p l o t l i b . u se ( ” TkAgg ” )
currency = ’ ’ ,
start year = 0
end year = 0
token = ’ ’
threshold = 0.01
agents = [ ]
historic text = ’ ’
historic title = ’’
cont = 0
data = None
l i v e = True
con = None
def trade () :
89
90 Source Code
g l o b a l currency , agents , l i v e
initiate traders ()
while l i v e :
time . s l e e p ( 3 )
try :
l a s t p r i c e = con . g e t l a s t p r i c e ( c u r r e n c y )
f o r a ge n t i n a g e n t s :
a ge n t . t r a d e ( l a s t p r i c e )
except :
time . s l e e p ( 1 0 )
con . c l o s e ( )
initiate traders ()
def i n i t i a t e t r a d e r s () :
g l o b a l a g e n t s , con , c u r r e n c y
def r u n h i s t o r i c () :
g l o b a l c u r r e n c y , s t a r t y e a r , en d y ea r , t h r e s h o l d ,
h i s t o r i c t e x t , h i s t o r i c t i t l e , data
d a t a s e t = dbc . g e t d a t a s e t ( c u r r e n c y , s t a r t y e a r , e n d y e a r )
dbc . r e s e t d a t a b a s e ( )
time . s l e e p ( 1 )
long ’ )
a g e n t s h o r t = Agent ( o r i g i n a l t h r e s h o l d=t h r e s h o l d , agent mode =’
short ’ )
f o r row i n d a t a s e t :
i d = row [ 0 ]
d a t e t i m e = dbc . d a t e t i m e t o f l o a t ( s t r ( row [ 2 ] ) , s t r ( row [ 3 ] ) )
b i d = f l o a t ( row [ 5 ] )
ask = f l o a t ( row [ 6 ] )
p r i c e = P r i c e ( id , ask , bid , d a t e t i m e )
agent long . trade ( price )
agent short . trade ( price )
dbc . g e t t o t a l s t a t s ( )
s t a t s d a t a = dbc . p r i n t s t a t s ( )
data = dbc . g e t l i q u i d v a l u e ( )
time . s l e e p ( 1 )
historic text = \
f ’ Opened o r d e r s : { s t a t s d a t a . l o c [ 0 , ”OPENED ORDERS” ] } \ n\n ’
\
f ’ Cl osed o r d e r s : { s t a t s d a t a . l o c [ 0 , ”CLOSED ORDERS” ] } \ n\n ’
\
f ’ Orders c l o s e d with p r o f i t : { s t a t s d a t a . l o c [ 0 , ”
TAKE PROFIT ORDERS” ] } \ n\n ’ \
f ’ Orders c l o s e d with s t o p l o s s : { s t a t s d a t a . l o c [ 0 , ”
STOP LOSS ORDERS” ] } \ n\n ’ \
f ’ Percentage of closed orders : { s t a t s d a t a . l o c [ 0 , ”
CLOSED ORDERS PERCENTAGE” ] } %\n\n ’ \
f ’ P e r c e n t a g e o f o r d e r s c l o s e d with p r o f i t : { s t a t s d a t a . l o c
[ 0 , ”TAKE PROFIT PERCENTAGE” ] } %\n\n ’ \
f ’ P e r c e n t a g e o f o r d e r s c l o s e d with s t o p l o s s : { s t a t s d a t a .
l o c [ 0 , ”STOP LOSS PERCENTAGE” ] } %\n\n ’
h i s t o r i c t i t l e = f ’ { c u r r e n c y } r e s u l t s between { s t a r t y e a r } and
{ e n d y e a r }\n\n ’
print (0)
c l a s s Main ( tk . Tk) :
tk . Tk . init ( s e l f , ⇤ a r g s , ⇤⇤ kwargs )
tk . Tk . w m t i t l e ( s e l f , ’ AlphaPy ’ )
c o n t a i n e r = tk . Frame ( s e l f )
c o n t a i n e r . pack ( s i d e =”top ” , f i l l =’ both ’ , expand=True )
c o n t a i n e r . g r i d r o w c o n f i g u r e ( 0 , wei gh t =1)
c o n t a i n e r . g r i d c o l u m n c o n f i g u r e ( 0 , w ei gh t =1)
s e l f . f r a m e s = {}
f o r F i n ( StartPage , L i v e S t a r t , H i s t o r i c S t a r t , Live ,
H i s t o r i c , GraphPage ) :
frame = F( c o n t a i n e r , s e l f )
s e l f . f r a m e s [ F ] = frame
frame . g r i d ( row=0, column =0, s t i c k y =”nsew ” )
s e l f . show frame ( S t a r t P a g e )
d e f show frame ( s e l f , c o n t ) :
frame = s e l f . f r a m e s [ c o n t ]
frame . t k r a i s e ( )
def s t o p l i v e ( s e l f , cont ) :
g l o b a l con , l i v e
con . c l o s e ( )
l i v e = False
frame = s e l f . f r a m e s [ c o n t ]
frame . t k r a i s e ( )
d e f c h a n g e t o l i v e ( s e l f , cont , t o k e n v a r , c u r r e n c y v a r ) :
g l o b a l token , c u r r e n c y , l i v e
l i v e = True
token = t o k e n v a r . g e t ( )
currency aux = currency var . c u r s e l e c t i o n ()
currency = currency var . get ( currency aux )
x = t h r e a d i n g . Thread ( t a r g e t=t r a d e )
x . start ()
93
frame = s e l f . f r a m e s [ c o n t ]
frame . t k r a i s e ( )
d e f c h a n g e t o h i s t o r i c ( s e l f , cont , s t a r t , end , t h r e s h o l d v a r ,
currency var ) :
g l o b a l t h r e s h o l d , s t a r t y e a r , en d y ea r , c u r r e n c y
s t a r t y e a r = int ( s t a r t . get () )
e n d y e a r = i n t ( end . g e t ( ) )
threshold = f l o a t ( threshold var . get () )
run historic ()
frame = s e l f . f r a m e s [ c o n t ]
frame . t i t l e . c o n f i g ( t e x t= h i s t o r i c t i t l e )
frame . t e x t . c o n f i g ( t e x t=h i s t o r i c t e x t )
frame . t k r a i s e ( )
g l o b a l data
l i q u i d v a l u e = data [ ’BALANCE’ ] . t o l i s t ( )
d a t e s = data [ ’DATE’ ] . t o l i s t ( )
frame = s e l f . f r a m e s [ c o n t ]
frame . a . c l e a r ( )
frame . a . s e t t i t l e ( f ’ R e s u l t s o f { c u r r e n c y } with t h r e s h o l d {
t h r e s h o l d }\n\n ’ )
frame . a . p l o t ( d a t e s , l i q u i d v a l u e )
frame . canvas . draw ( )
frame . t k r a i s e ( )
c l a s s S t a r t P a g e ( tk . Frame ) :
def i n i t ( s e l f , parent , c o n t r o l l e r ) :
tk . Frame . i n i t ( s e l f , p a r e n t )
h i s t o r i c b u t t o n = t t k . Button ( s e l f , t e x t =” H i s t o r i c Trading
”,
command=lambda : c o n t r o l l e r .
show frame ( H i s t o r i c S t a r t ) )
h i s t o r i c b u t t o n . pack ( pady=50)
c l a s s L i v e S t a r t ( tk . Frame ) :
g l o b a l token
def i n i t ( s e l f , parent , c o n t r o l l e r ) :
tk . Frame . i n i t ( s e l f , p a r e n t )
t o k e n v a r = tk . S t r i n g V a r ( )
l a b e l = tk . Label ( s e l f , t e x t =” S e l e c t your c u r r e n c y ” , f o n t
=17)
l a b e l . pack ( pady =10 , padx=10)
c u r r e n c i e s = tk . S t r i n g V a r ( v a l u e =[ ’EUR/USD’ , ’GBP/USD’ , ’
USD/JPY ’ , ’EUR/JPY ’ , ’USD/EUR’ , ’BTC/USD ’ ] )
c u r r e n c y e n t r y = tk . L i s t b o x ( s e l f , l i s t v a r i a b l e=c u r r e n c i e s ,
h e i g h t =6)
c u r r e n c y e n t r y . pack ( )
s t a r t b u t t o n = t t k . Button ( s e l f , t e x t =” S t a r t ” , command=
lambda : c o n t r o l l e r . c h a n g e t o l i v e ( Live , t o k e n v a r ,
c l a s s H i s t o r i c S t a r t ( tk . Frame ) :
def i n i t ( s e l f , parent , c o n t r o l l e r ) :
tk . Frame . i n i t ( s e l f , p a r e n t )
l a b e l = tk . Label ( s e l f , t e x t =” S e l e c t s t a r t y e a r ” , f o n t =17)
l a b e l . pack ( pady=5)
s t a r t d a t e = t t k . Combobox ( s e l f , v a l u e s = ( ’ 2 0 0 1 ’ , ’ 2 0 0 2 ’ ,
’2003 ’ , ’2004 ’ , ’2005 ’ , ’2006 ’ , ’2007 ’ , ’2008 ’ ,
’2009 ’ , ’2010 ’ ,
’2011 ’ , ’2012 ’ ,
’2013 ’ ,
’2014 ’ , ’2015 ’ ,
’2016 ’ ,
96 Source Code
’2017 ’ , ’2018 ’ ,
’2019 ’) )
s t a r t d a t e . pack ( )
f i n i s h d a t e = t t k . Combobox ( s e l f , v a l u e s = ( ’ 2 0 0 1 ’ , ’ 2 0 0 2 ’ ,
’2003 ’ , ’2004 ’ , ’2005 ’ , ’2006 ’ , ’2007 ’ , ’2008 ’ ,
’2009 ’ , ’2010 ’ ,
’2011 ’ , ’2012 ’ ,
’2013 ’ ,
’2014 ’ , ’2015 ’ ,
’2016 ’ ,
’2017 ’ , ’2018 ’ ,
’2019 ’) )
f i n i s h d a t e . pack ( )
l a b e l = tk . Label ( s e l f , t e x t =” S e l e c t a t h r e s h o l d ” , f o n t =17)
l a b e l . pack ( pady=7, padx=10)
t h r e s h o l d e n t r y = t t k . Combobox ( s e l f , v a l u e s = ( ’ 0 . 0 1 ’ ,
’0.005 ’ , ’0.0025 ’ , ’0.0015 ’) )
t h r e s h o l d e n t r y . pack ( )
l a b e l = tk . Label ( s e l f , t e x t =” S e l e c t your c u r r e n c y ” , f o n t
=17)
l a b e l . pack ( pady=7, padx=10)
c u r r e n c i e s = tk . S t r i n g V a r ( v a l u e =[ ’ e u r u s d ’ , ’ gbp usd ’ , ’
usd cad ’ , ’ u s d j p y ’ , ’ eur gbp ’ , ’ e u r j p y ’ , ’ e u r c h f ’ ] )
c u r r e n c y e n t r y = tk . L i s t b o x ( s e l f , l i s t v a r i a b l e=c u r r e n c i e s ,
h e i g h t =7)
c u r r e n c y e n t r y . pack ( )
s t a r t b u t t o n = t t k . Button ( s e l f , t e x t =” S t a r t ” , command=
lambda : c o n t r o l l e r . c h a n g e t o h i s t o r i c ( H i s t o r i c ,
start date , finish date , threshold entry ,
currency entry ) )
s t a r t b u t t o n . pack ( pady =10 , padx=10)
c l a s s L i v e ( tk . Frame ) :
def i n i t ( s e l f , parent , c o n t r o l l e r ) :
tk . Frame . i n i t ( s e l f , p a r e n t )
c l a s s H i s t o r i c ( tk . Frame ) :
g l o b a l s t a r t y e a r , en d y ea r , h i s t o r i c t e x t , c u r r e n c y ,
historic title
def i n i t ( s e l f , parent , c o n t r o l l e r ) :
tk . Frame . i n i t ( s e l f , p a r e n t )
s e l f . t i t l e = tk . Label ( s e l f , t e x t=h i s t o r i c t i t l e , f o n t=
LARGE FONT)
s e l f . t i t l e . pack ( pady =20 , padx=10)
g r a p h b u t t o n = t t k . Button ( s e l f , t e x t =”Graph o f t h e l i q u i d
v a l u e ” , command=lambda : c o n t r o l l e r . c h a n g e t o g r a p h (
GraphPage ) )
g r a p h b u t t o n . pack ( pady =10 , padx=10)
c l a s s GraphPage ( tk . Frame ) :
g l o b a l s t a r t y e a r , en d y ea r , h i s t o r i c t e x t , c u r r e n c y ,
h i s t o r i c t i t l e , threshold
def i n i t ( s e l f , parent , c o n t r o l l e r ) :
tk . Frame . i n i t ( s e l f , p a r e n t )
99
p l t . s t y l e . us e ( ’ seaborn ’ )
p l t . l e g e n d ( l o c =’ b es t ’ , prop ={’ s i z e ’ : 20})
s e l f . f i g = F i g u r e ( f i g s i z e =(12 , 5 ) , d p i =100)
s e l f . a . x a x i s . s e t m a j o r l o c a t o r ( mdates . YearLocator ( ) )
s e l f . a . x a x i s . s e t m a j o r f o r m a t t e r ( mdates . DateFormatter ( ’%Y
%m’ ) )
s e l f . canvas = FigureCanvasTkAgg ( s e l f . f i g , s e l f )
s e l f . canvas . g e t t k w i d g e t ( ) . pack ( s i d e=tk .BOTTOM, f i l l =tk .
BOTH, expand=True )
s e l f . canvas . t k c a n v a s . pack ( s i d e=tk .TOP, f i l l =tk .BOTH,
expand=True )
app = Main ( )
app . mainloop ( )
C l a s s DBConnection
#!/ u s r / b i n / python3
import pymysql as s q l
import d a t e t i m e a s dt
import m a t p l o t l i b a s mpl
import pandas a s pd
s e l e c t e d c u r r e n c y = None
onlinehost = ’160.153.142.193 ’
o n l i n e u s e r = ’ Forex DB TFG ’
o n l i n e p a s s w o r d = ’UVx . P2Ps6V@L+.JL ’
o n l i n e d b = ’ Forex DB TFG ’
o n l i n e p o r t = 3306
100 Source Code
balance = 0.0
opened orders = 0
closed orders = 0
take profit orders = 0
stop loss orders = 0
current month = 1
c u r r e n t y e a r = 2001
e n d y e a r = 2019
s t a r t y e a r = 2001
try :
i f cursor . connection :
cursor . execute ( sentence )
return cursor . f e t c h a l l ()
else :
p r i n t (” i m p o s s i b l e to connect to the database ”)
except Exception as e :
return str ( e )
d e f d a t e t i m e t o f l o a t ( date , time ) :
”””
A u x i l i a r method used t o c o n v e r t a d a t e and a time i n t o a
f l o a t i n g time v a l u e ( time v a l u e t h a t i s n ’ t t i e d t o a
s p e c i f i c time zone )
101
r e t u r n s t r ( dt . d a t e t i m e . fromtimestamp ( f l o a t ) )
d e f g e t d a t a s e t ( c u r r e n c y , s t a r t y , end y ) :
g l o b a l db
global selected currency
global end year
global start year
global current year
p r i n t ( ” S e l e c t t h e d a t a s e t s t a r t y e a r ( min . 2 0 0 1 ) ” )
start year = start y
a s s e r t ( s t a r t y e a r >= 2001 and s t a r t y e a r <= 2 0 19 ) , ”{} , Not a
v a l i d s t a r t y e a r s e l e c t e d ” . format ( s t a r t y e a r )
current year = start year
s t a r t d a t e = ’{} 01 01 ’. format ( s t a r t y e a r )
p r i n t ( ” S e l e c t t h e d a t a s e t end y e a r (max . 2 0 1 9 ) ” )
102 Source Code
e n d y e a r = end y
a s s e r t ( e n d y e a r >= 2001 and s t a r t y e a r <= 2 0 19 ) , ”{} , Not a
v a l i d s t a r t y e a r s e l e c t e d ” . format ( s t a r t y e a r )
i f e n d y e a r != 2 0 1 9 :
e n d d a t e = ’{} 12 31 ’. format ( e n d y e a r )
else :
e n d d a t e = ’{} 03 31 ’. format ( e n d y e a r )
d a t a s e t = e x e c u t e s e n t e n c e ( g e t d a t a s e t s e n t e n c e , db . c u r s o r ( ) )
db . c u r s o r ( ) . c l o s e ( )
return dataset
o r d e r d a t e = f l o a t t o d a t e t i m e ( o r d e r . time )
o r d e r d a t e = o r d e r d a t e . s p l i t (” ”)
i f ( i n t ( o r d e r d a t e [ 1 ] ) != c u r r e n t m o n t h ) :
update stats ()
o p e n e d o r d e r s += 1
{} , \ ’ { } \ ’ , {} , {} , {} , {} , 0 ) ; ” . format (
selected currency ,
order . order id , order . open price ,
o r d e r . volume ,
f l o a t t o d a t e t i m e ( o r d e r . time ) ,
o r d e r . agent mode ,
order . threshold up ,
order . threshold down ,
order . event of creation ,
order . take profit ,
order . stop loss ,
order . l i q u i d i t y ,
order . inventory )
e x e c u t e s e n t e n c e ( i n s e r t s e n t e n c e , db . c u r s o r ( ) )
p r i n t ( ”DATABASE: J u s t c r e a t e d t h e d a t a b a s e buy o r d e r with t h e
f o l l o w i n g i d : { } ” . format ( o r d e r . o r d e r i d ) )
d e f c r e a t e d a t a b a s e s e l l o r d e r ( id , s e l l p r i c e , c l o s e t i m e ,
close event name , c l o s e o p t i o n ) :
g l o b a l db
global closed orders
global take profit orders
global stop loss orders
global selected currency
i f ( i n t ( o r d e r d a t e [ 1 ] ) != c u r r e n t m o n t h ) :
update stats ()
c l o s e d o r d e r s += 1
i f ( c l o s e o p t i o n == ’ StopLoss ’ ) :
s t o p l o s s o r d e r s += 1
e l i f ( c l o s e o p t i o n == ’ T a k e P r o f i t ’ ) :
t a k e p r o f i t o r d e r s += 1
104 Source Code
o r i g i n a l o r d e r = e x e c u t e s e n t e n c e ( s e l e c t s e n t e n c e , db . c u r s o r ( )
)
e x e c u t e s e n t e n c e ( d e l e t e s e n t e n c e , db . c u r s o r ( ) )
f o r row i n o r i g i n a l o r d e r :
i n s e r t s e n t e n c e = ”INSERT INTO {} CLOSED ORDERS (
ORIGINAL ID , OPEN PRICE, CLOSE PRICE , VOLUME,
OPEN DATE TIME, CLOSE DATE TIME, AGENT MODE,
THRESHOLD UP, THRESHOLD DOWN, OPEN EVENT, CLOSE EVENT,
TAKE PROFIT, STOP LOSS , LIQUIDITY , INVENTORY,
CLOSE OPTION) ” \
”VALUES ( \ ’ { } \ ’ , {} , {} , {} , \ ’ { } \ ’ ,
\ ’ { } \ ’ , \ ’ { } \ ’ , {} , {} , \ ’ { } \ ’ ,
\ ’ { } \ ’ , {} , {} , {} , {} , \ ’ { } \ ’ ) ; ” .
format (
s e l e c t e d c u r r e n c y , row [ 0 ] , row [ 1 ] , s e l l p r i c e , row [ 2 ] ,
row [ 3 ] , f l o a t t o d a t e t i m e ( c l o s e t i m e ) , row [ 4 ] ,
row [ 5 ] , row [ 6 ] , row [ 7 ] , c l o s e e v e n t n a m e , row [ 8 ] , row
[ 9 ] , row [ 1 0 ] , row [ 1 1 ] , c l o s e o p t i o n )
e x e c u t e s e n t e n c e ( i n s e r t s e n t e n c e , db . c u r s o r ( ) )
s e l l o r d e r = e x e c u t e s e n t e n c e ( s e l e c t o r d e r i n s e r t e d , db . c u r s o r
() )
i f o p e n e d o r d e r s != 0 :
105
i f c l o s e d o r d e r s != 0 :
i f c u r r e n t m o n t h >= 1 and c u r r e n t m o n t h <= 9 :
i n s e r t s e n t e n c e = ”””
INSERT INTO {} MONTHLY STATS (
MONTH YEAR, OPENED ORDERS,
CLOSED ORDERS,
TAKE PROFIT ORDERS,
STOP LOSS ORDERS,
CLOSED ORDERS PERCENTAGE,
TAKE PROFIT PERCENTAGE,
STOP LOSS PERCENTAGE)
VALUES(\ ’0{} {}\ ’ , {} , {} , {} ,
{} , {} , {} , {})
” ” ” . format ( s e l e c t e d c u r r e n c y ,
current month , c u r r e n t y e a r
, opened orders ,
closed orders ,
take profit orders ,
stop loss orders ,
closed orders /
opened orders ⇤ 100 ,
take profit orders /
c l o s e d o r d e r s ⇤ 100 ,
stop loss orders /
c l o s e d o r d e r s ⇤ 100)
closed orders /
opened orders ⇤ 100 ,
take profit orders /
c l o s e d o r d e r s ⇤ 100 ,
stop loss orders /
c l o s e d o r d e r s ⇤ 100)
e x e c u t e s e n t e n c e ( i n s e r t s e n t e n c e , db . c u r s o r ( ) )
e l i f c l o s e d o r d e r s == 0 :
i f c u r r e n t m o n t h >= 1 and c u r r e n t m o n t h <= 9 :
i n s e r t s e n t e n c e = ”””
INSERT INTO {} MONTHLY STATS (
MONTH YEAR, OPENED ORDERS,
CLOSED ORDERS,
TAKE PROFIT ORDERS,
STOP LOSS ORDERS,
CLOSED ORDERS PERCENTAGE,
TAKE PROFIT PERCENTAGE,
STOP LOSS PERCENTAGE)
VALUES(\ ’0{} {}\ ’ , {} , 0 , 0 ,
0 , 0 , 0 , 0)
” ” ” . format ( s e l e c t e d c u r r e n c y ,
current month , c u r r e n t y e a r
, opened orders )
opened orders = 0
closed orders = 0
107
i f c u r r e n t m o n t h == 1 2 :
current month = 1
c u r r e n t y e a r += 1
else :
c u r r e n t m o n t h += 1
o p e n e d o r d e r s = e x e c u t e s e n t e n c e ( s e l e c t a l l , db . c u r s o r ( ) )
current = 0.0
f o r row i n o p e n e d o r d e r s :
i f row [ 4 ] == ’ long ’ :
c u r r e n t += ( c u r r e n t p r i c e ⇤ row [ 2 ] row [ 1 ] ⇤ row [ 2 ] )
e l i f row [ 4 ] == ’ s h o r t ’ :
c u r r e n t += ( row [ 1 ] ⇤ row [ 2 ] c u r r e n t p r i c e ⇤ row [ 2 ] )
o p e n e d o r d e r s = e x e c u t e s e n t e n c e ( s e l e c t a l l , db . c u r s o r ( ) )
current = 0.0
f o r row i n s e l l o r d e r :
i f row [ 7 ] == ’ long ’ :
c l o s e t i m e = row [ 6 ]
b a l a n c e += row [ 4 ] ⇤ ( row [ 3 ] row [ 2 ] )
108 Source Code
e l i f row [ 7 ] == ’ s h o r t ’ :
c l o s e t i m e = row [ 6 ]
b a l a n c e += row [ 4 ] ⇤ ( row [ 2 ] row [ 3 ] )
f o r row i n o p e n e d o r d e r s :
i f row [ 4 ] == ’ long ’ :
c u r r e n t += row [ 2 ] ⇤ ( c u r r e n t p r i c e row [ 1 ] )
e l i f row [ 4 ] == ’ s h o r t ’ :
c u r r e n t += row [ 2 ] ⇤ ( row [ 1 ] current price )
i n s e r t b a l a n c e ( balance + current , c l o se t i m e )
p r i c e = round ( p r i c e , 3 )
i n s e r t s e n t e n c e = ”INSERT INTO {} BALANCE (BALANCE, DATE)
VALUES( { } , \ ’ { } \ ’ ) ; ” . format ( s e l e c t e d c u r r e n c y , p r i c e ,
e x e c u t e s e n t e n c e ( i n s e r t s e n t e n c e , db . c u r s o r ( ) )
def g e t l i q u i d v a l u e () :
g l o b a l db
global end year
global start year
mpl . s t y l e . use ( ’ c l a s s i c ’ )
data = pd . r e a d s q l ( s e l e c t s e n t e n c e , db , p a r s e d a t e s =[ ’DATE’ ] )
i f window ==0:
109
window = 1
r e t u r n data
def g e t t o t a l s t a t s () :
g l o b a l db
global selected currency
update stats ()
s e l e c t s e n t e n c e = ”””
SELECT SUM(OPENED ORDERS) , SUM(
CLOSED ORDERS) , SUM(TAKE PROFIT ORDERS)
, SUM(STOP LOSS ORDERS)
FROM {} MONTHLY STATS WHERE OPENED ORDERS
IS NOT NULL;
” ” ” . format ( s e l e c t e d c u r r e n c y )
t o t a l = e x e c u t e s e n t e n c e ( s e l e c t s e n t e n c e , db . c u r s o r ( ) )
f o r row i n t o t a l :
opened = row [ 0 ]
c l o s e d = row [ 1 ]
t a k e p r o f i t e s = row [ 2 ]
s t o p l o s s e s = row [ 3 ]
c l o s e d p e r c e n t a g e = c l o s e d / opened ⇤ 100
i f ( c l o s e d != 0 ) :
t p p e r c e n t a g e = t a k e p r o f i t e s / c l o s e d ⇤ 100
s l p e r c e n t a g e = s t o p l o s s e s / c l o s e d ⇤ 100
else :
tp percentage = 0.0
sl percentage = 0.0
”VALUES ( \ ’EXECUTION\ ’ , \ ’ { } \ ’ , \ ’ { } \ ’ , \ ’ { } \ ’ ,
\ ’ { } \ ’ , {} , {} , {}) ; ” . format (
selected currency ,
e x e c u t e s e n t e n c e ( i n s e r t s e n t e n c e , db . c u r s o r ( ) )
def p r i n t s t a t s () :
g l o b a l db
data = pd . r e a d s q l ( s e l e c t s e n t e n c e , db )
r e t u r n data
def r e s e t g l o b a l v a r i a b l e s () :
g l o b a l balance , opened orders , c l o s e d o r d e r s ,
t a k e p r o f i t o r d e r s , s t o p l o s s o r d e r s , current month
balance = 0.0
opened orders = 0
closed orders = 0
take profit orders = 0
stop loss orders = 0
current month = 1
112 Source Code
Class h i s t o r i c C l a s s e s
import random
import s t r i n g
import math
from math import exp
from math import log
from math import pow
from math import sqrt
c l a s s Agent :
”””
Trader , manages p o s i t i o n s
”””
# u n i t s i z e i s t h e p e r c e n t a g e o f t h e cash t h a t w i l l be b i d
i n each p o s i t i o n
s e l f . u n i t s i z e = 10
s e l f . inventory = 0
s e l f . e v e n t s r e c o r d e r = EventsRecorder ( o r i g i n a l t h r e s h o l d ,
’ up ’ )
”””
t h i s method opens new p o s i t i o n s o r c l o s e s a l r e a d y opened
p o s i t i o n s depending on i n t r i n s i c s e v e n t s
directionalChangeToDown : d i r e c t i o n a l change t o down mode
directionalChangeToDown : d i r e c t i o n a l change t o down mode
downOvershoot : o v e r s h o o t g i v e n a downwards d i r e c t i o n
upOvershoot : o v e r s h o o t g i v e n a upwards d i r e c t i o n
: param p r i c e :
: return :
”””
s e l f . l i q u i d i t y i n d i c a t o r . run ( p r i c e )
i f e v e n t != ’ NOevent ’ :
i f e v e n t == ’ downOvershoot ’ o r e v e n t == ’
directionalChangeToUp ’ :
s e l f . open new order ( price , event )
e l i f e v e n t == ’ upOvershoot ’ :
s e l f . s e l l o p e n e d p o s i t i o n s ( price , event )
else :
i f e v e n t == ’ upOvershoot ’ o r e v e n t == ’
directionalChangeToDown ’ :
s e l f . open new order ( price , event )
e l i f e v e n t == ’ downOvershoot ’ :
s e l f . s e l l o p e n e d p o s i t i o n s ( price , event )
return 0
i f e v e n t i s ’ downOvershoot ’ :
t a k e p r o f i t = s e l f . c o m p u t e t a k e p r o f i t ( p r i c e . ask ,
s e l f . e v e n t s r e c o r d e r . t h r e s h o l d d o w n , ’ long ’ )
s t o p l o s s = s e l f . c o m p u t e s t o p l o s s ( p r i c e . ask , s e l f
. e v e n t s r e c o r d e r . t h r e s h o l d d o w n , ’ long ’ )
n e w o r d e r = Order ( p r i c e . ask , s e l f . u n i t s i z e ⇤
s i z e a d j u s t m e n t , p r i c e . time , s e l f . agent mode ,
s e l f . events recorder .
threshold up , s e l f .
events recorder .
t h r e s h o l d d o w n , event ,
take profit , stop loss , s e l f .
liquidity indicator . liquidity
, s e l f . inventory )
e l i f e v e n t i s ’ directionalChangeToUp ’ :
t a k e p r o f i t = s e l f . c o m p u t e t a k e p r o f i t ( p r i c e . ask ,
s e l f . e v e n t s r e c o r d e r . t h r e s h o l d u p , ’ long ’ )
s t o p l o s s = s e l f . c o m p u t e s t o p l o s s ( p r i c e . ask , s e l f
. e v e n t s r e c o r d e r . t h r e s h o l d u p , ’ long ’ )
n e w o r d e r = Order ( p r i c e . ask , s e l f . u n i t s i z e ⇤
s i z e a d j u s t m e n t , p r i c e . time , s e l f . agent mode ,
s e l f . events recorder .
threshold up , s e l f .
events recorder .
t h r e s h o l d d o w n , event ,
take profit , stop loss , s e l f .
liquidity indicator . liquidity
, s e l f . inventory )
s e l f . o p e n e d o r d e r s l o n g . append ( n e w o r d e r )
s e l f . i n v e n t o r y += s e l f . u n i t s i z e ⇤ s i z e a d j u s t m e n t
s e l f . events recorder . adjust thresholds ( s e l f . inventory )
s e l f . liquidity indicator . adjust thresholds ( s e l f .
inventory )
dbc . c r e a t e d a t a b a s e b u y o r d e r ( n e w o r d e r )
else :
size adjustment = s e l f . liquidity i nd icat o r .
adjust sizing ()
i f e v e n t i s ’ upOvershoot ’ :
115
t a k e p r o f i t = s e l f . c o m p u t e t a k e p r o f i t ( p r i c e . ask ,
s e l f . e v e n t s r e c o r d e r . threshold up , ’ short ’ )
s t o p l o s s = s e l f . c o m p u t e s t o p l o s s ( p r i c e . ask , s e l f
. e v e n t s r e c o r d e r . threshold up , ’ short ’ )
n e w o r d e r = Order ( p r i c e . ask , s e l f . u n i t s i z e ⇤
s i z e a d j u s t m e n t , p r i c e . time , s e l f . agent mode ,
s e l f . events recorder .
threshold up , s e l f .
events recorder .
t h r e s h o l d d o w n , event ,
take profit , stop loss , s e l f .
liquidity indicator . liquidity
, s e l f . inventory )
e l i f e v e n t i s ’ directionalChangeToDown ’ :
t a k e p r o f i t = s e l f . c o m p u t e t a k e p r o f i t ( p r i c e . ask ,
s e l f . e v e n t s r e c o r d e r . threshold down , ’ short ’ )
s t o p l o s s = s e l f . c o m p u t e s t o p l o s s ( p r i c e . ask , s e l f
. e v e n t s r e c o r d e r . threshold down , ’ short ’ )
n e w o r d e r = Order ( p r i c e . ask , s e l f . u n i t s i z e ⇤
s i z e a d j u s t m e n t , p r i c e . time , s e l f . agent mode ,
s e l f . events recorder .
threshold up , s e l f .
events recorder .
t h r e s h o l d d o w n , event ,
take profit , stop loss , s e l f .
liquidity indicator . liquidity
, s e l f . inventory )
s e l f . o p e n e d o r d e r s s h o r t . append ( n e w o r d e r )
s e l f . inventory = s e l f . u n i t s i z e ⇤ size adjustment
s e l f . events recorder . adjust thresholds ( s e l f . inventory )
s e l f . liquidity indicator . adjust thresholds ( s e l f .
inventory )
dbc . c r e a t e d a t a b a s e b u y o r d e r ( n e w o r d e r )
dbc . c r e a t e d a t a b a s e s e l l o r d e r ( o r d e r . o r d e r i d ,
p r i c e . bid , p r i c e . time , event , ’ T a k e P r o f i t
’)
e l i f p r i c e . b i d <= o r d e r . s t o p l o s s :
s e l f . o p e n e d o r d e r s l o n g . remove ( o r d e r )
s e l f . i n v e n t o r y = o r d e r . volume
s e l f . events recorder . adjust thresholds ( s e l f .
inventory )
s e l f . liquidity indicator . adjust thresholds (
s e l f . inventory )
dbc . c r e a t e d a t a b a s e s e l l o r d e r ( o r d e r . o r d e r i d ,
p r i c e . bid , p r i c e . time , event , ’ StopLoss ’ )
else :
for order in s e l f . opened orders short :
i f p r i c e . ask <= o r d e r . t a k e p r o f i t :
s e l f . o p e n e d o r d e r s s h o r t . remove ( o r d e r )
s e l f . i n v e n t o r y += o r d e r . volume
s e l f . events recorder . adjust thresholds ( s e l f .
inventory )
s e l f . liquidity indicator . adjust thresholds (
s e l f . inventory )
dbc . c r e a t e d a t a b a s e s e l l o r d e r ( o r d e r . o r d e r i d ,
p r i c e . ask , p r i c e . time , event , ’ T a k e P r o f i t
’)
e l i f p r i c e . ask >= o r d e r . s t o p l o s s :
s e l f . o p e n e d o r d e r s s h o r t . remove ( o r d e r )
s e l f . i n v e n t o r y += o r d e r . volume
s e l f . events recorder . adjust thresholds ( s e l f .
inventory )
s e l f . liquidity indicator . adjust thresholds (
s e l f . inventory )
dbc . c r e a t e d a t a b a s e s e l l o r d e r ( o r d e r . o r d e r i d ,
p r i c e . ask , p r i c e . time , event , ’ StopLoss ’ )
d e f c o m p u t e t a k e p r o f i t ( s e l f , p r i c e , t h r e s h o l d , mode ) :
i f mode i s ’ long ’ :
r e t u r n exp ( l o g ( p r i c e ) + t h r e s h o l d )
e l i f mode i s ’ s h o r t ’ :
r e t u r n exp ( l o g ( p r i c e ) threshold )
d e f c o m p u t e s t o p l o s s ( s e l f , p r i c e , t h r e s h o l d , mode ) :
i f mode i s ’ long ’ :
117
c l a s s EventsRecorder :
”””
Records e v e n t s ( o v e r s h o o t s and d i r e c t i o n a l changes )
”””
i f s e l f . market mode == ’ up ’ :
118 Source Code
i f p r i c e . g e t b i d ( ) > s e l f . extreme :
s e l f . extreme = p r i c e . g e t b i d ( )
s e l f . compute expected directional change ()
i f price . get bid () > s e l f . expected overshoot price
:
s e l f . r e f e r e n c e = s e l f . extreme
s e l f . compute expected overshoot ()
r e t u r n ’ upOvershoot ’
e l i f p r i c e . g e t a s k ( ) <= s e l f .
expected directional change price :
s e l f . r e f e r e n c e = s e l f . extreme = p r i c e . g e t a s k ( )
s e l f . market mode = ’ down ’
s e l f . compute expected directional change ()
s e l f . compute expected overshoot ()
r e t u r n ’ directionalChangeToDown ’
else :
i f p r i c e . g e t a s k ( ) < s e l f . extreme :
s e l f . extreme = p r i c e . g e t a s k ( )
s e l f . compute expected directional change ()
e l i f p r i c e . g e t b i d ( ) >= s e l f .
expected directional change price :
s e l f . r e f e r e n c e = s e l f . extreme = p r i c e . g e t b i d ( )
s e l f . market mode = ’ up ’
s e l f . compute expected directional change ()
s e l f . compute expected overshoot ()
r e t u r n ’ directionalChangeToUp ’
r e t u r n ’ NOevent ’
) + s e l f . threshold up )
else :
s e l f . e x p e c t e d o v e r s h o o t p r i c e = exp ( l o g ( s e l f . r e f e r e n c e
) s e l f . threshold down )
#LONG
i f i n v e n t o r y >= 150 and inventory < 300:
s e l f . threshold up = s e l f . o r i g i n a l t h r e s h o l d ⇤ 0.75
s e l f . threshold down = s e l f . original threshold ⇤ 1.5
e l i f i n v e n t o r y >= 3 0 0 :
s e l f . threshold up = s e l f . original threshold ⇤ 0.5
s e l f . threshold down = self . original threshold ⇤ 2
#SHORT
e l i f inventory > 300 and i n v e n t o r y <= 150:
s e l f . threshold up = s e l f . original threshold ⇤ 1.5
s e l f . threshold down = s e l f . o r i g i n a l t h r e s h o l d ⇤ 0.75
e l i f i n v e n t o r y <= 300:
s e l f . threshold up = s e l f . original threshold ⇤ 2
s e l f . threshold down = s e l f . o r i g i n a l t h r e s h o l d ⇤ 0.5
else :
s e l f . threshold up = s e l f . original threshold
s e l f . threshold down = s e l f . o r i g i n a l t h r e s h o l d
cl ass Price :
”””
This c l a s s r e p r e s e n t s t h e p r i c e o b j e c t , which w i l l be p a s s e d
t o t h e a g en t with e v e r y new
t i c k o f t h e market .
120 Source Code
”””
def clone ( s e l f ) :
r e t u r n P r i c e ( s e l f . id , s e l f . ask , s e l f . bid , s e l f . time )
def get id ( s e l f ) :
return s e l f . id
class LiquidityIndicator :
s e l f . r e f e r e n c e = None
s e l f . mode = ’ up ’
d e f compute h1 ( s e l f ) :
r e t u r n exp( s e l f . o r i g i n a l t h r e s h o l d ⇤ 2 . 5 2 5 7 9 / s e l f .
o r i g i n a l t h r e s h o l d ) ⇤ l o g ( exp( s e l f . o r i g i n a l t h r e s h o l d
⇤ 2.52579 / s e l f . o r i g i n a l t h r e s h o l d ) ) (1.0 exp(
s e l f . o r i g i n a l t h r e s h o l d ⇤ 2.52579 / s e l f .
o r i g i n a l t h r e s h o l d ) ) ⇤ log (1 exp( s e l f .
o r i g i n a l t h r e s h o l d ⇤ 2.52579 / s e l f . o r i g i n a l t h r e s h o l d )
)
d e f compute h2 ( s e l f ) :
r e t u r n exp( s e l f . o r i g i n a l t h r e s h o l d ⇤ 2 . 5 2 5 7 9 / s e l f .
o r i g i n a l t h r e s h o l d ) ⇤ pow ( l o g ( exp( s e l f .
o r i g i n a l t h r e s h o l d ⇤ 2.52579 / s e l f . o r i g i n a l t h r e s h o l d )
) , 2) (1.0 exp( s e l f . o r i g i n a l t h r e s h o l d ⇤ 2 . 5 2 5 7 9 /
s e l f . o r i g i n a l t h r e s h o l d ) ) ⇤ pow ( l o g ( 1 exp( s e l f .
o r i g i n a l t h r e s h o l d ⇤ 2.52579 / s e l f . o r i g i n a l t h r e s h o l d )
) ,2) s e l f . H1 ⇤ s e l f . H1
def a d j u s t s i z i n g ( s e l f ) :
i f e v e n t != ’ NOevent ’ :
d e f run ( s e l f , p r i c e ) :
i f not s e l f . i n i t i a l i z e d :
s e l f . extreme = s e l f . r e f e r e n c e = p r i c e . g e t m i d ( )
s e l f . i n i t i a l i z e d = True
s e l f . c o m p u t e l i q u i d i t y ( ’ NOevent ’ )
i f s e l f . mode i s ’ down ’ :
i f math . l o g ( p r i c e . g e t b i d ( ) / s e l f . extreme ) >= s e l f .
threshold up :
s e l f . mode = ’ up ’
s e l f . extreme = p r i c e . g e t b i d ( )
s e l f . reference = price . get bid ()
s e l f . compute liquidity ( ’ directionalChange ’ )
i f p r i c e . g e t a s k ( ) < s e l f . extreme :
s e l f . extreme = p r i c e . g e t a s k ( )
e l i f s e l f . mode i s ’ up ’ :
i f math . l o g ( p r i c e . g e t a s k ( ) / s e l f . extreme ) <= s e l f .
threshold down :
s e l f . mode = ’ down ’
s e l f . extreme = p r i c e . g e t a s k ( )
s e l f . reference = price . get ask ()
s e l f . compute liquidity ( ’ directionalChange ’ )
i f p r i c e . g e t b i d ( ) > s e l f . extreme :
s e l f . extreme = p r i c e . g e t b i d ( )
threshold up ⇤ 2.52579:
s e l f . r e f e r e n c e = s e l f . extreme
s e l f . compute liquidity ( ’ overshoot ’ )
#SHORT
e l i f inventory > 300 and i n v e n t o r y <= 150:
s e l f . threshold up = s e l f . original threshold ⇤ 1.5
s e l f . threshold down = s e l f . o r i g i n a l t h r e s h o l d ⇤ 0.75
e l i f i n v e n t o r y <= 300:
s e l f . threshold up = s e l f . original threshold ⇤ 2
s e l f . threshold down = s e l f . o r i g i n a l t h r e s h o l d ⇤ 0.5
else :
s e l f . threshold up = s e l f . original threshold
s e l f . threshold down = s e l f . o r i g i n a l t h r e s h o l d
c l a s s Order :
”””
This c l a s s r e p r e s e n t s a p o s i t i o n
P o s i t i o n s w i l l be opened and c l o s e d by a g e n t s when o p e r a t i n g
”””
\ end { verbatim }
Class classesBroker
c l a s s Agent :
”””
Trader , manages p o s i t i o n s
”””
# u n i t s i z e i s t h e p e r c e n t a g e o f t h e cash t h a t w i l l be b i d
i n each p o s i t i o n
s e l f . u n i t s i z e = 100
s e l f . inventory = 0
s e l f . e v e n t s r e c o r d e r = EventsRecorder ( s e l f .
original threshold )
s e l f . b r o k e r = con
125
def trade ( s e l f , l a s t p r i c e ) :
”””
t h i s method opens new p o s i t i o n s o r c l o s e s a l r e a d y opened
p o s i t i o n s depending on i n t r i n s i c s e v e n t s
directionalChangeToDown : d i r e c t i o n a l change t o down mode
directionalChangeToDown : d i r e c t i o n a l change t o down mode
downOvershoot : o v e r s h o o t g i v e n a downwards d i r e c t i o n
upOvershoot : o v e r s h o o t g i v e n a upwards d i r e c t i o n
: return :
”””
print ( f ’ l a s t price i s : { l a s t p r i c e } ’)
# c a l l l i q u i d i t y here
s e l f . l i q u i d i t y i n d i c a t o r . run ( l a s t p r i c e )
i f e v e n t != ’ NOevent ’ :
i f e v e n t == ’ downOvershoot ’ o r e v e n t == ’
directionalChangeToUp ’ :
s e l f . open new order ( )
e l i f e v e n t == ’ upOvershoot ’ :
self . sell opened positions ( last price )
else :
pass
else :
i f e v e n t == ’ upOvershoot ’ o r e v e n t == ’
directionalChangeToDown ’ :
s e l f . open new order ( )
126 Source Code
e l i f e v e n t == ’ downOvershoot ’ :
self . sell opened positions ( last price )
else :
pass
return 0
def s e l l o p e n e d p o s i t i o n s ( s e l f , l a s t p r i c e ) :
o r d e r s l i s t = s e l f . b r o k e r . g e t o p e n p o s i t i o n s ( kind =’ l i s t ’ )
for order in o r d e r s l i s t :
p r i n t ( f ’ i n s i d e f o r l o o p i n s e l l o r d e r with p l : { o r d e r
[” visiblePL ”]} ’)
i f s e l f . s t o p l o s s ( order , l a s t p r i c e ) or s e l f . p r o f i t (
order ) :
s e l f . broker . c l o s e t r a d e ( order [ ’ tradeId ’ ] , order [ ’
amountK ’ ] )
s e l f . adjust inventory ( order )
def s t o p l o s s ( s e l f , order , l a s t p r i c e ) :
i f o r d e r [ ’ isBuy ’ ] :
s t o p = o r d e r [ ’ open ’ ] ⇤ ( 1 (0.15 (0.1 ( self .
liquidity indicator . liquidity ⇤ self .
e v e n t s r e c o r d e r . threshold up ⇤ 10) ) ) )
r e t u r n True i f l a s t p r i c e [ ’ Ask ’ ] < s t o p e l s e F a l s e
else :
s t o p = o r d e r [ ’ open ’ ] ⇤ ( 1 + ( 0 . 1 5 (0.1 ( self .
liquidity indicator . liquidity ⇤ self .
127
def p r o f i t ( s e l f , order ) :
r e t u r n True i f o r d e r [ ’ v i s i b l e P L ’ ] > 0 . 5 e l s e F a l s e
c l a s s EventsRecorder :
”””
Records e v e n t s ( o v e r s h o o t s and d i r e c t i o n a l changes )
”””
i f s e l f . market mode == ’ up ’ :
i f l a s t p r i c e . Bid > s e l f . e x p e c t e d o v e r s h o o t p r i c e :
s e l f . r e f e r e n c e = s e l f . extreme
s e l f . compute expected overshoot ()
r e t u r n ’ upOvershoot ’
e l i f l a s t p r i c e . Ask <= s e l f .
expected directional change price :
s e l f . r e f e r e n c e = s e l f . extreme = l a s t p r i c e . Ask
s e l f . market mode = ’ down ’
s e l f . compute expected directional change ()
s e l f . compute expected overshoot ()
r e t u r n ’ directionalChangeToDown ’
else :
i f l a s t p r i c e . Ask < s e l f . extreme :
s e l f . extreme = l a s t p r i c e . Ask
s e l f . compute expected directional change ()
i f l a s t p r i c e . Ask < s e l f . e x p e c t e d o v e r s h o o t p r i c e :
s e l f . r e f e r e n c e = s e l f . extreme
s e l f . compute expected overshoot ()
r e t u r n ’ downOvershoot ’
e l i f l a s t p r i c e . Bid >= s e l f .
expected directional change price :
s e l f . r e f e r e n c e = s e l f . extreme = l a s t p r i c e . Bid
s e l f . market mode = ’ up ’
s e l f . compute expected directional change ()
s e l f . compute expected overshoot ()
r e t u r n ’ directionalChangeToUp ’
r e t u r n ’ NOevent ’
get expected OS ’
i f s e l f . market mode == ’ up ’ :
s e l f . e x p e c t e d o v e r s h o o t p r i c e = exp ( l o g ( s e l f . r e f e r e n c e
) + s e l f . threshold up )
else :
s e l f . e x p e c t e d o v e r s h o o t p r i c e = exp ( l o g ( s e l f . r e f e r e n c e
) s e l f . threshold down )
class LiquidityIndicator :
self . l i q u i d i t y = 0.0
self .K = 5 0 . 0
self . a l p h a w e i g h t = math . exp ( 2.0 / ( s e l f .K + 1 . 0 ) )
self . H1 = s e l f . compute h1 ( )
self . H2 = s e l f . compute h2 ( )
self . surprise = 0.0
self . i n i t i a l i z e d = False
self . extreme = None
self . r e f e r e n c e = None
self . mode = ’ up ’
d e f compute h1 ( s e l f ) :
r e t u r n exp( s e l f . o r i g i n a l t h r e s h o l d ⇤ 2 . 5 2 5 7 9 / s e l f .
original threshold ) ⇤ log (
exp( s e l f . o r i g i n a l t h r e s h o l d ⇤ 2 . 5 2 5 7 9 / s e l f .
original threshold )) (
1.0 exp( s e l f . o r i g i n a l t h r e s h o l d ⇤
2.52579 / s e l f . o r i g i n a l t h r e s h o l d ) ) ⇤
log (
1 exp( s e l f . o r i g i n a l t h r e s h o l d ⇤ 2 . 5 2 5 7 9 / s e l f .
original threshold ))
d e f compute h2 ( s e l f ) :
r e t u r n exp( s e l f . o r i g i n a l t h r e s h o l d ⇤ 2 . 5 2 5 7 9 / s e l f .
o r i g i n a l t h r e s h o l d ) ⇤ pow (
l o g ( exp( s e l f . o r i g i n a l t h r e s h o l d ⇤ 2 . 5 2 5 7 9 / s e l f .
original threshold ) ) , 2.0) (
1.0 exp( s e l f . o r i g i n a l t h r e s h o l d ⇤
2.52579 / s e l f . o r i g i n a l t h r e s h o l d ) ) ⇤
pow (
log (1.0 exp( s e l f . o r i g i n a l t h r e s h o l d ⇤ 2 . 5 2 5 7 9 /
s e l f . original threshold ) ) , 2.0) s e l f . H1 ⇤ s e l f . H1
def a d j u s t s i z i n g ( s e l f ) :
return 1
i f e v e n t != ’ NOevent ’ :
s e l f . s u r p r i s e = s e l f . compute surprise ( event )
s e l f . l i q u i d i t y = 1.0 self .
normal distribution cumulative (
s q r t ( s e l f .K) ⇤ ( s e l f . s u r p r i s e s e l f . H1) / s q r t (
s e l f . H2) )
if x > 6.0:
return 1.0
if x < 6.0:
return 0.0
b1 = 0 . 3 1 9 3 8 1 5 3
b2 = 0.356563782
b3 = 1 . 7 8 1 4 7 7 9 3 7
b4 = 1.821255978
b5 = 1 . 3 3 0 2 7 4 4 2 9
p = 0.2316419
c2 = 0 . 3 9 8 9 4 2 3
a = abs ( x )
t = 1.0 / (1.0 + a ⇤ p)
b = c2 ⇤ exp (( x ) ⇤ ( x / 2 . 0 ) )
n = ( ( ( ( b5 ⇤ t + b4 ) ⇤ t + b3 ) ⇤ t + b2 ) ⇤ t + b1 ) ⇤ t
n = 1.0 b ⇤ n
if x < 0.0:
n = 1.0 n
132 Source Code
return n
d e f run ( s e l f , l a s t p r i c e ) :
i f not s e l f . i n i t i a l i z e d :
s e l f . extreme = s e l f . r e f e r e n c e = ( l a s t p r i c e . Ask +
l a s t p r i c e . Bid ) / 2
s e l f . i n i t i a l i z e d = True
s e l f . c o m p u t e l i q u i d i t y ( ’ NOevent ’ )
i f s e l f . mode i s ’ down ’ :
i f math . l o g ( l a s t p r i c e . Bid / s e l f . extreme ) >= s e l f .
threshold up :
s e l f . mode = ’ up ’
s e l f . extreme = l a s t p r i c e . Bid
s e l f . r e f e r e n c e = l a s t p r i c e . Bid
s e l f . compute liquidity ( ’ directionalChange ’ )
e l i f s e l f . mode i s ’ up ’ :
i f math . l o g ( l a s t p r i c e . Ask / s e l f . extreme ) <= s e l f .
threshold down :
s e l f . mode = ’ down ’
s e l f . extreme = l a s t p r i c e . Ask
s e l f . r e f e r e n c e = l a s t p r i c e . Ask
s e l f . compute liquidity ( ’ directionalChange ’ )
else :
s e l f . threshold up = s e l f . original threshold
s e l f . threshold down = s e l f . o r i g i n a l t h r e s h o l d
Results of the Efficiency Tests
AUD/USD
135
136 Results of the Efficiency Tests
EUR/CHF
EUR/GBP
138 Results of the Efficiency Tests
EUR/JPY
EUR/USD
GBP/USD
USD/CAD
USD/JPY
CHF/JPY
EUR/CAD
GBP/CHF
GBP/JPY
NZD/JPY
NZD/USD
USD/CHF
XAG/USD
XAU/USD
Once Python is installed, install pip downloading the file ’get-pip.py’ from the web-
site https://bootstrap.pypa.io/get-pip.py to a folder on your computer. Open a command
prompt and navigate to the folder containing get-pip.py. Run the following command:
$ python get-pip.py
You can verify that Pip was installed correctly by opening a command prompt and
entering the following command:
$ pip -v
153
154 How to set up the project
.0.2 Mac OS X
Install brew by pasting the following in a macOS Terminal prompt.
You can check if the installation worked by typing the terminal command:
$ python3 –version
Python 3.7.2
$ pip –version
$ python –Version
Python 3.7.2
Once the installation is completed, verify the installation by checking the pip version:
$ pip3 –version
The version number may vary, but it will look something like this:
$ virtualenv my venv
$ my venv\Scripts\activate
.0.5 Mac OS X
Type the following commands:
$ virtualenv my venv
$ source my venv/bin/activate
$ virtualenv venv
$ source venv/bin/activate
https://github.com/luis3zc/TFG/archive/master.zip
$ python3 Main.py
Bibliography
[2] QuantInsti, “History of algorithmic trading, hft and news based trading.”
https://www.quantinsti.com/blog/history-algorithmic-trading-hft, 2015.
[4] U.S. Presidential Task Force on Market Mechanisms, “Report of the Presidential Task
Force on Market Mechanisms : submitted to The President of the United States,
The Secretary of the Treasury, and The Chairman of the Federal Reserve Board.”
https://archive.org/details/reportofpresiden01unit, 1988.
[8] J. Montier, The Little Book of Behavioral Investing: How not to be your own worst
enemy. John Wiley & Sons, Ltd., 2010.
[10] J. Treanor, “The 2010 ’flash crash’: how it unfolded,” The Guardian, 2015.
[12] Bank for International Settlements, Monetary and Economic Department, “Foreign
exchange turnover in April 2016.” https://www.bis.org/publ/rpfx16.htm, 2016.
159
160 BIBLIOGRAPHY
[16] G. Dorgan, “SNB Losses: 1.85 Billion Francs in Just One Day, 231 Francs, 250$ per
Inhabitants.” https://snbchf.com/2012/12/snb-losses-dec18/, 2012.
[18] B. Mandelbrot and H. Taylor, “On the Distribution of Stock Price Di↵erences,” Oper-
ations Research, vol. 15, no. 6, 1967.
[20] U. Muller, M. Dacorogna, R. Davé, O. Pictet, R. Olsen, and J. Ward, “Fractals and
Intrinsic Time - A Challenge to Econometricians.,” Olsen and Associates, vol. 1, no. 2,
1997.
[21] D. Guillaume, M. Dacorogna, R. Davé, U. Müller, R. Olsen, and O. Pictet, “From the
bird’s eye to the microscope: A survey of new stylized facts of the intra-daily foreign
exchange markets,” Finance Stoch, vol. 1, no. 2, 1997.
[22] A. Golub, J. Glattfelder, and R. Olsen, “The Alpha Engine: Designing an Automated
Trading Algorithm.” https://papers.ssrn.com/sol3/papers.cfm?abstract id=2951348,
2017.
[24] G. J., D. A., and O. R., “Patterns in high-frequency FX data: Discovery of 12 empirical
scaling laws,” Quantitative Finance, vol. 11, no. 4, 2008.
[26] A. Dupuis and R. Olsen, “High Frequency Finance: Using Scaling Laws to Build Trading
Models,” Handbook of Exchange Rates, 2012.
BIBLIOGRAPHY 161
[27] P. S., The Evaluation of the Trend-Following Directional Change with the Trailing Stop
and Major-Trend-Adjusted Strategies on Algorithmic Trading in the Foreign Exchange
Markets. PhD thesis, University of Essex, 2015.
[30] T. Cover and J. Thomas, Elements of Information Theory. New York, NY, USA: Wiley-
Interscience, 1991.
[32] H. Pfister, J. Soriaga, and P. Siegel, On the achievable information rates of finite state
ISI channels, vol. 5. GLOBECOM’01. IEEE Global Telecommunications Conference,
2001.
[33] L. Cam, “The central limit theorem around 1935,” Statistical Science, vol. 1, pp. 78–91,
1986.
[35] J. Golub A., Glattfelder, V. Pertov, and R. Olsen, “Waiting Times and Number of
Directional Changes in Intrinsic Time Framework.,” Algorithmic Finance, 2017.
[41] P. Kruchten, “The 4+1 view model of architecture,” IEEE Softw., vol. 12, pp. 42–50,
Nov. 1995.
[42] J. Rumbaugh, I. Jacobson, and G. Booch, Unified Modeling Language Reference Manual,
The (2Nd Edition). Pearson Higher Education, 2004.
162 BIBLIOGRAPHY
3.1 EUR/USD mid-prices time series defined by physical time and intrinsic time.
The sampling period is over November 5th, 2009. For intrinsic time, the
number of events is 30 determined by a threshold size of 0.1%. [17] . . . . . 10
3.2 Market mode. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.3 Threshold. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.4 Intrinsic events. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.5 Bid and ask. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.6 Scaling law for and ! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.7 Coastline trading. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.8 The transition network of states in the directional-change approach represen-
tation of the price trajectories ! [22] . . . . . . . . . . . . . . . . . . . . . . 21
3.9 Daily Profit & Loss of the Alpha Engine, across 23 currency pairs, for eight
years. [22] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.10 Monte Carlo simulation of the number of directional changes N as a function
of the asymmetric directional change thresholds up and down . [22] . . . . . . 28
3.11 Di↵erent behaviour of the intrinsic event detection using fixed (left) and asym-
metric (right) thresholds. [22] . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.12 Stop Loss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.13 Trailing Stop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.14 Market prices evolution between Janaury 2014 and March 2019 of the EUR-
GBP and EUR-USD markets. . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.15 Results of the executions on the currency EUR-GBP with threshold 0.025%. 42
3.16 Results of the executions on the currency EUR-GBP with threshold 0.075%. 42
3.17 Results of the executions on the currency EUR-USD with threshold 0.025%. 43
3.18 Results of the executions on the currency EUR-USD with threshold 0.075%. 43
163
164 LIST OF FIGURES
3.1 Stats of the orders managed by the algorithm between 2001 and 2019. . . . . 19
5.1 Stats of the orders managed by the algorithm in the last test. . . . . . . . . 73
5.2 Table of the Closed Rate for all the currencies in the Version 1 . . . . . . . . 77
5.3 Table of the Closed Rate for all the currencies in the Version 2 . . . . . . . . 78
5.4 Table of the Closed Rate for all the currencies in the Version 3 . . . . . . . . 79
5.5 Table of the Closed Rate for all the currencies in the Version 4 . . . . . . . . 81
167
List of Algorithms
169
Index
170
INDEX 171
Scaling law, 15
Second order of informativeness, 22
Shape parameter, 16
Short trading, 12
Short trading strategy, 17
Sniper and Guerilla, 3
Software architecture design, 52
Spread, 14
Stealth, 3
Stop-loss, 34
Surprise, 20
Surprise equation, 21