Re-posted from: http://juliacomputing.com/blog/2017/08/22/algorithmic-trading.html

A detailed version of this article appeared in the Automated Trader magazine.

What makes algorithmic trading particularly challenging is that it

needs to be a polymath to do it well. It requires a unique blend of

mathematics, finance, databases, operating systems, and street

smarts. Julia makes it easier. Prototype in Julia, use the most

sophisticated algorithms to trade once in a while, or the simplest

ones to trade with high frequency, backtest at scale, and deploy in

production extracting the most out of the best hardware. The

JuliaFin suite of

packages makes this entire workflow smooth and

easy. JuliaDB makes it easy to store and query

historical data and write in-database real-time

algorithms. Miletus is a domain

specific language to value complex financial instruments without

programming the mathematics from scratch. While the

Bloomberg API

wrapper package makes it easy to query real-time data from the

Bloomberg terminal, it is equally easy to consume data from other

feeds and sockets in a variety of formats. Finally, with

JuliaRun, all of this

can be put into production and scaled with a single click. This blog

will introduce each of these packages from a trading perspective and

tie it all up with an arbitrage example.

Now, you may say that is all great, but does Julia integrate with

Excel, because otherwise there is no way my users will use it? That’s

why we will start off with a quick overview of

JuliaInXL.

# Excel integration – Deployment to front office teams

Regardless of where one sits within the financial services industry,

one product that is ubiquitous is Microsoft® Excel®. Analysts and

traders often want library functionalities to be accessible from

Excel. Julia Computing’s JuliaInXL package provides an extension to

Excel that brings the power of the Julia language and its ecosystem

into the familiar spreadsheet work

environment. JuliaInXL

allows users to launch Julia processes, load modules and execute

functions directly from the Excel UI. In Figure 01 below, we show an

example of how a user can construct new functionality in the IDE,

launch a JuliaInXL server and execute Julia functions against that

JuliaInXL server session.

_{Figure 01: Julia and Excel working together}

# Connectors for historical data sources for tick data and aggregated data

To access historical financial data from within Julia there are

options available to either use community-developed packages or

commercially-supported options from Julia Computing. In the set of

community-developed packages, the

Quandl.jl package allows

users to access Quandl’s online financial data feeds using your own

unique authentication token for the Quandl service. Quandl.jl provides

functionality for both searching and retrieving information from

Quandl’s database which covers a broad set of categories for financial

and economic datasets. Similarly, the

YStockData.jl package

allows for retrieving historical securities pricing information from

Yahoo! Finance. (Although the Yahoo! Finance API does not give access

to current data anymore, it is still possible to download historical

data.) As part of the JuliaFin suite of offerings from Julia

Computing, the

Blpapi.jl package

implements a full wrapper interface of Bloomberg Professional’s BLPAPI

for C/C++, as well as high level implementations of the popular bdp

and bdh functions for retrieving historical daily data and intraday

tick and bar functions for retrieving tick level data (Listing 1).

# JuliaDB – Store and query historical data. Write in-database real-time algorithms.

Developing an effective trading strategy normally involves testing the

strategy using historical data before going into production using live

data. Building a robust platform for backtesting requires integration

of a number of distinct components for accessing, storing and querying

data libraries for statistical modelling, numerical optimisation and

financial analytics. Additionally, incorporating visualisation

packages can help lead to clear insights. The Julia ecosystem includes

a variety of packages that address each step in developing and

deploying a backtesting workflow.

## Efficient warehousing and querying of time series and other structured data

An effective backtesting system not only requires access to historical

financial data, but also needs means of storing, persisting and

querying that data. Financial time series datasets are often highly

structured data, but can also be composed of messy datasets that

include missing values or multiple columns of temporally mismatched

data. Handling financial time series requires data structures that can

be efficiently read, stored, queried and extracted for this type of

naturally ordered data. Algorithms need to be able to handle missing

or non-overlapping data in an effective manner.

In this section, we focus on a package that has recently been

developed and open sourced by Julia Computing, aiming to provide a

user-friendly and high-performing table interface for interacting with

column oriented data

sets. JuliaDB.jl is a

distributed columnar data table implementation that builds on a

framework for parallel, in-memory and out- of-core execution and

provides a column store data table implementation along with fast data

input/output from csv-files.

JuliaDB enables large datasets spread through numerous files across a

cluster of Julia worker processes to be ingested into a single,

distributed table data structure. A JuliaDB table separates columns

into two distinct sets wherein one set forms a sorted index and the

remaining columns are the associated data columns. The table data

structure is equivalent to an N-dimensional sparse array with an

interface that follows Julia’s array API as closely as possible, but

also allows for index values to have non-integer data types. A JuliaDB

table provides a mapping of index tuples to individual elements in one

or more data columns, essentially the individual row elements in the

data columns.

**Listing 1**

```
# Create a Bloomberg session over a particular IP
address and port number
IP = “localhost”
Port = 8194
session = createSession(IP, Port)
### Reference data request
# Required parameters of reference data request:
# ticker names
tickers = [“IBM US Equity”, “AAPL US Equity”]
# elds requested
elds = [“PX_Open”, “PX_High”, “PX_Last”]
# Call the bdp function by providing session,
tickers and elds variables
Response = bdp(session, tickers, elds)
# The response from bdp function is a Julia type
ReferenceDataResponse object
# Initializing tickers and elds arrays to be passed
to the bdp function call
tickers = [“IBM US Equity”, “AAPL US Equity”]
elds = [“PX_Last”, “PX_Open”]
# Getting the response in variable ‘Response’
Response = bdp(Session, tickers, elds)
# extracting response data by providing ticker and
eld name
ibmLastPrice = Response[“IBM US Equity”, “PX_Last”]
ibmOpenPrice = Response[“IBM US Equity”, “PX_Open”]
appleLastPrice = Response[“AAPL US Equity”,
“PX_Last”]
appleOpenPrice = Response[“AAPL US Equity”,
“PX_Open”]
```

**Listing 2**

```
_
_ _ _(_)_ | A fresh approach to technical computing
(_) | (_) (_) | Documentation: https://docs.julialang.org
_ _ _| |_ __ _ | Type "?help" for help.
| | | | | | |/ _ | |
| | |_| | | | (_| | | Version 0.6.0-rc1.0 (2017-05-07 00:00 UTC)
_/ |\__'_|_|_|\__'_| | Official http://julialang.org/ release
|__/ | x86_64-pc-linux-gnu
julia> addprocs(20);
julia> @everywhere using JuliaDB
julia> dir = "/home/juser/TrueFX/data";
julia> files = glob("*.csv",dir)
1380-element Array{String,1}:
"/home/juser/TrueFX/data/AUDJPY-2009-05.csv"
"/home/juser/TrueFX/data/AUDJPY-2009-06.csv"
"/home/juser/TrueFX/data/AUDJPY-2009-07.csv"
"/home/juser/TrueFX/data/AUDJPY-2009-08.csv"
"/home/juser/TrueFX/data/AUDJPY-2009-09.csv"
"/home/juser/TrueFX/data/AUDJPY-2009-10.csv"
"/home/juser/TrueFX/data/AUDJPY-2009-11.csv"
"/home/juser/TrueFX/data/AUDJPY-2009-12.csv"
"/home/juser/TrueFX/data/AUDJPY-2010-01.csv"
⋮
"/home/juser/TrueFX/data/USDJPY-2016-05.csv"
"/home/juser/TrueFX/data/USDJPY-2016-06.csv"
"/home/juser/TrueFX/data/USDJPY-2016-07.csv"
"/home/juser/TrueFX/data/USDJPY-2016-08.csv"
"/home/juser/TrueFX/data/USDJPY-2016-09.csv"
"/home/juser/TrueFX/data/USDJPY-2016-10.csv"
"/home/juser/TrueFX/data/USDJPY-2016-11.csv"
"/home/juser/TrueFX/data/USDJPY-2016-12.csv"
julia> a = ingest(files, dir, colnames=["pair","timestamp","bid","ask"], indexcols=[1,2],
colparsers=Dict("pair" => TextParse.StrRange, "timestamp" => Dates.DateTime,
"bid" => Float32, "ask" => Float32))
Reading 1380 csv files totalling 237.217 GiB...
DTable with 5539994782 rows in 1380 chunks:
pair timestamp │ bid ask
───────────────────────────────────┼───────────────
"AUD/JPY" 2009-05-01T00:00:00.31 │ 72.061 72.092
"AUD/JPY" 2009-05-01T00:00:00.318 │ 72.062 72.09
"AUD/JPY" 2009-05-01T00:00:00.361 │ 72.066 72.092
"AUD/JPY" 2009-05-01T00:00:00.528 │ 72.061 72.087
"AUD/JPY" 2009-05-01T00:00:00.547 │ 72.061 72.087
...
julia> a["GBP/USD", DateTime(2016,6,15):Dates.Minute(5):DateTime(2016,7,1)]
DTable with 1 chunks:
pair timestamp │ bid ask
───────────────────────────────┼─────────────────
"GBP/USD" 2016-06-15T07:40:00 │ 1.41645 1.41657
"GBP/USD" 2016-06-15T10:35:00 │ 1.41995 1.4201
"GBP/USD" 2016-06-17T11:45:00 │ 1.42951 1.42968
"GBP/USD" 2016-06-20T07:40:00 │ 1.45941 1.45954
"GBP/USD" 2016-06-20T18:10:00 │ 1.46716 1.46724
```

The index columns in JuliaDB tables are automatically sorted

lexicographically from left to right, which allows for extremely fast

data extraction on data sets that have a natural order to their index

values, a common scenario for financial time- series data. JuliaDB

provides a set of functions for efficient selection, aggregation,

permutation and conversion of data along one or more of the index

dimensions of a given table. Whenever possible, operations on the

columns of a JuliaDB table happen in the individual Julia process

where a subset of data is already located. While JuliaDB is fully

capable of automatically resorting data between processes when

necessary, providing the system with advanced knowledge of how on-disk

data sets should be partitioned can improve performance.

Listing 2 is an example of loading JuliaDB across a cluster of 20

Julia worker processes, ingesting more than seven years worth of

foreign exchange rate data that was obtained from

TrueFX. A simple indexing operation is used to

extract a subset of the table.

In an example presented in the final section, we will walk through how

one can go about integrating JuliaDB with other packages from the

Julia ecosystem to build an efficient and high-performing backtesting

system.

# Miletus – Model, price and analyze individual as well as baskets of securities

The ability to price and hedge a variety of securities requires access

to an extensive set of financial modelling and simulation tools. These

must reflect the diverse range of possible contract terms that can be

used in defining individual securities and baskets of

securities. Mathematical models need to reflect the conditions under

which the market can operate. When speed of development and execution

are both critical, traders need access to both pre-built libraries of

commonly used contracts and models, as well as functionality for

quickly building models for new contracts under changing market

conditions.

The Julia package ecosystem provides all of the foundational

mathematical and statistical functionality necessary to build

financial models of any desired complexity. In addition it includes a

set of packages specifically focused on the construction, modelling

and time-series analytics of financial securities. The JuliaStats

organisation includes packages covering basic probability and

statistics, model fitting, Monte Carlo analysis and foundational

machine learning tools. With specific regards to time series

analytics, the

MarketTechnicals.jl,

Indicators.jl and

TimeModels.jl packages

implement a variety of algorithms commonly utilised in technical

analysis, including moving averages, momentum and volatility

indicators, rolling statistical calculations and GARCH models.

In the realm of financial contract definition, modelling and pricing,

Julia Computing has developed

Miletus.jl

as part of its

JuliaFin

offering. Miletus is a package that consists of a domain specific

language for financial contract definition inspired by the research

work of Peyton-Jones and Eber. Miletus allows for complex financial

contracts to be constructed from a combination of a few simple

primitive components and operations. When viewed through the lens of

functional programming, this basic set of primitive objects and

operations form a set of ‘combinators’ that can be used to create more

complex financial instruments, including equities, options, currencies

and bonds of various kinds.

In addition, Miletus includes a decoupled set of valuation model

routines that can be applied to combinations of contract

primitives. These combinators and valuation routines are implemented

through the use of Julia’s user-defined types, generic programming and

multiple dispatch capabilities.

Some existing implementations of financial contract modelling

environments (created in languages such as Haskell or OCaml) rely

heavily on pure functional programming for the contract definition

language, but may then switch to a second language (such as C++, Java,

APL) for implementation of valuation processes. Miletus differs in

that it leverages Julia’s strong type system and multiple dispatch

capabilities to both express these contract primitive constructs and

provide for generation of efficient valuation code. As seen elsewhere

in the Julia ecosystem, Miletus solves the two-language problem with

regards to defining and modelling financial contracts.

In Listing 3 we show an example of how to construct and value a basic

European call option in terms of the primitive constructs available in

Miletus, as well as convenient, high- level constructors.

Now we can create a few basic operations using the type constructors

provided by Miletus, shown in Listing 4. These basic primitives can

be combined into higher level operations as displayed in Listing 5.

**Listing 3**

```
# Import the library
julia> using Miletus
import Miletus: When, Give, Receive, Buy,
Both, At, Either, Zero
```

**Listing 4**

```
# Receive an amount of 100 USD
julia> x=Receive(100USD)
Amount
└─100USD
# Pay is the opposite of Receive
julia> x=Pay(100USD)
Give
└─Amount
└─100USD
# Models are constructed and valued on a generic
SingleStock type
julia> s=SingleStock()
SingleStock
```

**Listing 5**

```
# Acquisition of a stock by paying 100USD
julia> x=Both(s, Pay(100USD))
Both
├─SingleStock
└─Give
└─Amount
└─100USD
# Which is equivalent to buying the stock
julia> x=Buy(s, 100USD)
Both
├─SingleStock
└─Give
└─Amount
└─100USD
# The notion of optionality is expressed by a choice
of two outcomes
julia> x=Either(s, Zero())
Either
├─SingleStock
└─Zero
```

**Listing 6**

```
julia> x=When(At(Date("2017-12-25")),
Receive(100USD))
When
├─{==}
│ ├─DateObs
│ └─2017-12-25
└─Amount
└─100USD
```

**Listing 7**

```
julia> x=When(At(Date("2017-12-25")),
Either(Buy(s, 100USD), Zero()))
When
├─{==}
│ ├─DateObs
│ └─2017-12-25
└─Either
├─Both
│ ├─SingleStock
│ └─Give
│ └─Amount
│ └─100USD
└─Zero
julia> eucall = EuropeanCall(Date("2017-12-25"),
SingleStock(), 100USD)
When
├─{==}
│ ├─DateObs
│ └─2017-12-25
└─Either
├─Both
│ ├─SingleStock
│ └─Give
│ └─Amount
│ └─100USD
└─Zero
```

Another important aspect of any contract is the notion of time. In

Listing 6 we define a temporal condition on which to receive a

payment of 100 USD. Combining that temporal condition with optionality

defines a basic European call option, which is demonstrated in Listing 7.

**Listing 8**

```
julia> gbmm = GeomBMModel(today(), 100.0USD, 0.1,
0.05, .15)
Geometric Brownian Motion Model
-------------------------------
S_0 = 100.0USD
T = 2017-03-14
Yield Constant Continuous Curve with r = 0.1,
T = 2017-03-14
Carry Constant Continuous Curve with r = 0.05,
σ = 0.15
julia> value(gbmm, eucall)
7.054679704161716USD
```

**Listing 9**

```
julia> using Miletus, Gadfly, Colors
import Miletus: Both, Give, Contract, WhenAt,
value
```

**Listing 10**

```
julia> expirydate = Date("2017-12-25")
startdate = Date("2017-12-1")
interestrate = 0.05
carryrate = 0.1
Volatility = 0.15 K1 = 98.0USD
K2 = 100.0USD
K3 = 102.0USD
L = 11 # Layers in the binomial lattice
price = K1-1USD:0.1USD:K3+1USD
```

**Listing 11**

```
julia> function payoff_curve(c, d::Date, prices)
payoff = [value(GeomBMModel(d, x, 0.0, 0.0,
0.0), c) for x in prices]
p = [x.val for x in payoff]
r = [x.val for x in prices]
return r, p
end
```

To price an option requires a valuation model. In Listing 8 we define a simple Geometric Brownian Motion

model (commonly referred to as the Black-Scholes equation) and value our European call option using that

model.

Having defined a basic call option, more complex payoffs can be

created through combinations of multiple options. Option spreads

consist of various combinations of call and put options having

different strike prices and/or expiry dates. We give examples of a few

different common option spread strategies. First, as shown in Listing 9,

let’s load the packages we will need to construct, visualise and

value our spreads.

Next, let’s define a few parameters that we will use when constructing

the different component options of our spread payoffs and valuation

model, including a range of strike prices we will use to visualise the

payoff curves (Listing 10).Then, in Listing 11, we define a function

that allows for calculating the payoff at expiry.

**Listing 12**

```
julia> function butterfly_call(expiry::Date, K1, K2, K3)
@assert K1 < K2 < K3
c1 = EuropeanCall(expiry, SingleStock(), K1)
c2 = EuropeanCall(expiry, SingleStock(), K2)
c3 = EuropeanCall(expiry, SingleStock(), K3)
Both(Both(c1,c3), Give(Both(c2,c2)))
end
julia> bfly1 = butterfly_call(expirydate, K1, K2, K3)
julia> s, p_bfly1 = payoff_curve(bfly1, expirydate, price)
call₁ = EuropeanCall(expirydate, SingleStock(), K₁)
call₂ = EuropeanCall(expirydate, SingleStock(), K₂)
call₃ = EuropeanCall(expirydate, SingleStock(), K₃)
s₁,cp₁ = payoff_curve(call₁, expirydate, price)
s₂,cp₂ = payoff_curve(call₂, expirydate, price)
s₃,cp₃ = payoff_curve(call₃, expirydate, price)
blk = colorant"black"
red = colorant"red"
grn = colorant"green"
blu = colorant"blue"
plot(layer(x=s , y=p_bfly1, Geom.line, Theme(default_color=blk, line_width=1.5mm)),
layer(x=s1, y=cp₁, Geom.line, Theme(default_color=red, line_width=1.0mm)),
layer(x=s₃, y=cp₃, Geom.line, Theme(default_color=grn, line_width=1.0mm)),
layer(x=s₂, y=-2cp₂, Geom.line, Theme(default_color=blu, line_width=1.0mm)), Guide.manual_color_key("", ["Butterfly Call", "call1", "call3", "-2call2"],
["black", "red", "green", "blue"]),
Guide.title("Butterfly Call Payoff Curve at Expiry"),
Guide.xlabel("Stock Price"), Guide.ylabel("Payoff"))
```

**Listing 13**

```
julia> volatility = 0.2
julia> gbmm = GeomBMModel(startdate, K2,
interestrate, carryrate, volatility)
Geometric Brownian Motion Model
-------------------------------
S0 = 100.0USD
T = 2017-12-1
Yield Constant Continuous Curve with r = 0.1,
T = 2017-12-1
Carry Constant Continuous Curve with r = 0.05,
T = 2017-12-1
σ = 0.15
julia> value(gbmm, b y1)
0.40245573232657295USD
```

**Note:** Julia allows for using the full unicode character set in its

source code. Special characters can be entered in many ways depending

on the input editor, but the primary method supported on the REPL is

to use TAB-completion with Tex expressions. So, for example, typing

\pi

A call butterfly consists of four options. It can be built by buying

two call options at the high and low strike price and selling two call

options at the central strike price.

Figure 02 shows the payoffs for both the call butterfly (in black) and

its constituent call options, produced by the code in Listing 12. The

options can be valued using a variety of models. For example, Listing

13 shows code for valuing the contract using the simple Geometric

Brownian Motion model.

## Optimal trading strategies

When developing any trading strategy, optimising with regards to

timing, price, volume, risk and other metrics is key to ensuring

profitable execution. Julia and its package ecosystem have unique

strengths in the area of mathematical optimisation that are not found

in other technical computing language. Optimisation development in

Julia is coordinated through the JuliaOpt,

JuliaNLSolvers and

JuliaDiff communities.

The JuliaOpt and JuliaNLSolvers organisations contain packages, such

as Optim.jl,

LineSearches.jl,

LsqFit.jl and

NLsolve.jl, which are

implemented as liberally-licensed, pure Julia code, as well as

integrations with other best-of- breed commercial and open-source

optimisation libraries implemented in C, C++ and Fortran. The full

list of open- source and commercial optimisation solvers integrated

with Julia can be found on the JuliaOpt home page. Most of these

interface packages have implemented integrations into JuliaOpt’s

MathProgBase.jl

abstraction layer package. This provides users with both high-level,

one-shot functions for linear and mixed-integer programming, as well

as a solver- independent, low-level interface for implementing

advanced techniques requiring the efficient solution of sequential

linear programming problems.

_{Figure 02: Call butterfly payoff at expiry}

MathProgBase provides the solver-independent abstractions needed for

implementation of the JuMP.jl domain specific language for numerical

optimisation. JuMP is an award-

winning, domain-specific language for optimisation in Julia

implemented in the tradition of existing open source and commercial

modelling languages such as AMPL, GAMS, AIMMS, OPL and MPL. Unlike

these existing modelling languages, JuMP’s implementation as a

standard Julia package allows for easy integration of high-level

optimisation modelling within larger analytic workflows. Further down,

we will give an example of a basic FX arbitrage strategy that walks

through the use of JuMP and uses data pulled from JuliaDB.

In addition to traditional linear and nonlinear programming approaches

to mathematical optimisation, the current movement in machine learning

and deep learning is developing along a similar trajectory within

Julia. The JuliaML organisation encompasses low-level interfaces to

existing learning frameworks, such as

MXnet.jl,

TensorFlow.jl and

Knet.jl. Model abstraction

packages allow users to easily switch between frameworks, and high

level modelling tools provide concise representations of machine

learning models.

While early in its development, the

Flux.jl package is a Keras like

package that includes its own DSL for the definition of machine

learning models. It allows for switching between backends like MXNet

or TensorFlow and easily fits into a larger Julia workflow.

# Tying it all together

In this section we will show how to tie together a number of distinct

Julia packages into a workflow for determining basic arbitrage

opportunities in the FX markets. As a simple trading strategy for FX

arbitrage, we will be implementing a Julia version of an example from

Cornuejols and Tütüncü,

2006. In

this strategy, imbalances within exchange rates between multiple

currency pairs can be exploited by setting up a linear programming

optimisation problem defined with JuMP. In this problem structure, for

a given set of exchange rates at a particular point in time, a set of

linear constraint equations is constructed that define all of the

possible relationships for exchanging US dollars, Euros, British

pounds and Japanese yen for a trader starting with one US dollar in

net assets. For this example, additional constraints are added to

limit all currency amounts to be positive and to limit the number of

dollars returned to be 10,000 USD. Our optimisation problem will be

set to maximise the number of dollars returned.

This example builds upon the TrueFX data set that we loaded into a

distributed JuliaDB table previously.To construct our optimisation

problem in Julia, we first need to load a set of packages (Listing

14). In this case we are loading JuMP along with the GLPK.jl and

GLPKMathProgInterface.jl

packages. GLPK.jl is a wrapper

for the open-source Gnu Linear Programming Kit optimisation library

and the

GLPKMathProgInterface.jl

package implements the interface to MathProgBase.jl that enables use

of this solver from JuMP.

**Listing 14**

```
julia> using JuMP, GLPK, GLPKMathProgInterface;
```

**Listing 15**

```
julia> function fx_arbitrage(eurusd, eurgbp, eurjpy,
gbpusd, gbpjpy, usdjpy)
usdeur = 1.0/eurusd
usdgbp = 1.0/gbpusd
gbpeur = 1.0/eurgbp
jpyusd = 1.0/usdjpy
jpyeur = 1.0/eurjpy
jpygbp = 1.0/gbpjpy
m = JuMP.Model(solver = GLPKSolverLP(
msg_lev = GLPK.MSG_ERR))
@variables m begin
de; dp; dy; ed; ep; ey; pd; pe; py; yd;
ye; yp; d
end
@objective(m, Max, d)
@constraints(m, begin
d + de + dp + dy - eurusd*ed - gbpusd*pd
- jpyusd*yd == 1.0
ed + ep + ey - usdeur*de - gbpeur*pe
- jpyeur*ye == 0.0
pd + pe + py - usdgbp*dp - eurgbp*ep
- jpygbp*yp == 0.0
yd + ye + yp - usdjpy*dy - eurjpy*ey
- gbpjpy*py == 0.0
d <= 10000.0
de >= 0.0
dp >= 0.0
dy >= 0.0
ed >= 0.0
ep >= 0.0
ey >= 0.0
pd >= 0.0
pe >= 0.0
py >= 0.0
yd >= 0.0
ye >= 0.0
yp >= 0.0
end)
solve(m)
DE,DP,DY,D = getvalue(de), getvalue(dp),
getvalue(dy), getvalue(d)
ED,EP,EY = getvalue(ed), getvalue(ep),
getvalue(ey)
PD,PE,PY = getvalue(pd), getvalue(pe),
getvalue(py)
YD,YE,YP = getvalue(yd), getvalue(ye),
getvalue(yp)
return D, DE, DP, DY, ED, EP, EY, PD, PE,
PY, YD, YE, YP
end
fx_arbitrage (generic function with 1 method)
```

Next, we will define our optimisation problem within a function using

JuMP. Our function accepts a set of exchange rates as input arguments

and then constructs a JuMP model using GLPK as the linear programming

solver.To fit with the assumptions made in the Cornuejols and

Tütüncü example, we will work with only the bid prices for each

currency pair and also ignore transaction costs.

**Listing 16**

```
julia> bids = compute(map(IndexedTables.pick(:bid),
a),allowoverlap=false)
DTable with 5539994778 rows in 1380 chunks:
pair timestamp │
───────────────────────────────────┼───────
"AUD/JPY" 2009-05-01T00:00:00.31 │ 72.061
"AUD/JPY" 2009-05-01T00:00:00.318 │ 72.062
"AUD/JPY" 2009-05-01T00:00:00.361 │ 72.066
"AUD/JPY" 2009-05-01T00:00:00.528 │ 72.061
"AUD/JPY" 2009-05-01T00:00:00.547 │ 72.061
...
julia> @everywhere function veminutes(t)
w = trunc(t, Dates.Minute)
m = Dates.Minute(w).value % 5
w + Dates.Minute(5-m)
end
julia> bids_5m = compute(convertdim(bids, 2,
veminutes, agg = max))
DTable with 8274322 rows in 1380 chunks:
───────────────────────────────┬───────
"AUD/JPY" 2009-05-01T00:05:00 │ 72.092
"AUD/JPY" 2009-05-01T00:10:00 │ 72.26
"AUD/JPY" 2009-05-01T00:15:00 │ 72.264
"AUD/JPY" 2009-05-01T00:20:00 │ 72.151
"AUD/JPY" 2009-05-01T00:25:00 │ 72.21
```

_{Figure 03: Currency volumes traded over time}

To change our program for use with a different open-source or

commercial optimisation library, one only needs to change the solver

argument used when constructing the JuMP model. Creation of an

optimisation problem with JuMP is as simple as applying a few simple

macros to the model that create new symbolic variables, define an

objective function and apply a set constraints to those symbolic

variables. Once the problem is fully defined, executing the solve

function on the model variable transforms the defined fields of the

model into inputs suitable for use by GLPK. It then executes GLPK’s

linear programming solver and returns an optimal set of currency

values that meet the requirements of our objective function and

constraints. See the JuMP documentation for more information on its

capabilities for the construction and solution of optimisation

problems.

With our optimisation problem defined in Listing 15, we will now

transform and extract a subset of the data on which to execute our

arbitrage algorithm in Listing 16. First, we extract the bid data into

its own table, then we perform a windowing operation over a

five-minute interval for each currency pair to synchronise their

timestamps.

**Listing 17**

```
julia> t_5m = DateTime(2016,6,15):Dates.Minute(5):DateTime(2016,7,1)
2016-06-15T00:00:00:5 minutes:2016-07-01T00:00:00
julia> TS = gather(bids_5m["EUR/USD",t_5m]).index.columns[2];
julia> EURUSD = gather(bids_5m["EUR/USD",t_5m]).data;
julia> EURGBP = gather(bids_5m["EUR/GBP",t_5m]).data;
julia> EURJPY = gather(bids_5m["EUR/JPY",t_5m]).data;
julia> GBPUSD = gather(bids_5m["GBP/USD",t_5m]).data;
julia> GBPJPY = gather(bids_5m["GBP/JPY",t_5m]).data;
julia> USDJPY = gather(bids_5m["USD/JPY",t_5m]).data;
julia> D,DE,DP,DY,ED,EP,EY,PD,PE,PY,YD,YE,YP = fx_arbitrage(EURUSD[1], EURGBP[1], EURJPY[1], GBPUSD[1],
GBPJPY[1], USDJPY[1])
(10000.0, 1.5005627439278532e7, 0.0, 0.0, 0.0, 1.3384616979325693e7, 0.0, 1.063233813089466e7, 0.0, 0.0, 0.0,
0.0, 0.0)
julia> FM = map(fx_arbitrage, EURUSD, EURGBP, EURJPY, GBPUSD, GBPJPY, USDJPY);
julia> function fx_arbitrage_arrays(A,TS)
M = length(A)
D = Array{Float64}(M)
DE = Array{Float64}(M)
DP = Array{Float64}(M)
DY = Array{Float64}(M)
ED = Array{Float64}(M)
EP = Array{Float64}(M)
EY = Array{Float64}(M)
PD = Array{Float64}(M)
PE = Array{Float64}(M)
PY = Array{Float64}(M)
YD = Array{Float64}(M)
YE = Array{Float64}(M)
YP = Array{Float64}(M)
for m = 1:M
D[m],DE[m],DP[m],DY[m],ED[m],EP[m],EY[m],PD[m],PE[m],PY[m],YD[m],YE[m], YP[m] = (A[m]...)
end
IndexedTable(Columns(timestamp = TS),
end
Columns(DE=DE,DP=DP,DY=DY,ED=ED,EP=EP,PD=PD,PE=PE,PY=PY,YD=YD,YE=YE,YP=YP))
fx_arbitrage_arrays (generic function with 1 method)
julia> FM_arbitrage = fx_arbitrage_arrays(FM, TS)
```

Next, we index into the table for each currency pair over a two-week

subset of five-minute intervals and extract the resulting data columns

into their own arrays.The rate values in each of these arrays can be

passed individually into a single execution of our arbitrage

optimisation routine, or the routine can be mapped over every element

of these arrays. Finally, as shown in Listing 17, we execute a

separate routine that constructs a new IndexedTable for display of the

currencies exchanged as part of each optimisation at every timestamp

and plot the currency volumes traded over time for each trade in

Figure 03.

# Summing up – Why Julia for algorithmic trading

- Julia provides a high productivity and high performance language for both financial analytics and infrastructure.
- Julia solves the two-language problem for both development and deployment of automated trading systems.
- Julia allows easy development of libraries both within the Julia package ecosystem and by using other language functionality from the outside.
- Julia’s package ecosystem covers the entire analytics and backtesting workflow.

We have shown how to create financial models in Julia and the

performance of their implementation. Julia’s approach to technical

computing has excited hundreds of thousands of quantitative

programmers worldwide and we hope you will join their ranks.